diff -ur --new-file old/atm/BUGS new/atm/BUGS --- old/atm/BUGS Mon Sep 2 20:19:59 1996 +++ new/atm/BUGS Fri Sep 27 15:15:27 1996 @@ -1,9 +1,10 @@ -Known bugs and restrictions in version 0.17 +Known bugs and restrictions in version 0.19 =========================================== IP over ATM ----------- + - first ping freezes some systems (???) - kernel crashes badly if (remote) ARP server is set to local machine - clients don't always refresh their entry at ARP server (fixed ?) - IP interfaces must not be reconfigured while up @@ -13,7 +14,6 @@ request or such usually cures that) (fixed ?) - atmarpd shouldn't invalidate entries on the first timeout in valid state but rather try one revalidation request first - - CLIP (the old way of doing IP over ATM) isn't tested - Arequipa leaves stale SVCs if atmsigd has disappeared - creation of the hard_header isn't "clean" @@ -28,11 +28,12 @@ - there's currently no way to obtain SVC traffic parameters indicated by the remote party - SSCOP doesn't update the window properly - - data retrieval is broken in SSCOP (but that doesn't affect the UNI) ENI-155p driver --------------- + - TX freezes on some systems when starting atmsigd and ilmid (???) + - driver may hang under heavy load with LANE - shouldn't depend on sizeof(unsigned long) == 4 - sometimes doesn't unqueue RX PDUs when being tortured with aping (or, more generally, seems to mis-calculate buffer usage after CR errors, @@ -51,12 +52,13 @@ - still hangs from time to time when sending - support for multiple adapters per machine is untested - SONET/SDH framing support is untested - - timestamps should use uPD98401 timestamps - doesn't support single-copy in this release ATM over TCP ------------ + - is reported to hang under load + - signaling is reported not to work over ATMTCP - driver is very limited in functionality - system may crash if atmtcp is killed - can't run IP over ATM using ATM over TCP @@ -67,7 +69,7 @@ - single copy currently uses massive amounts of brute force to flush TLBs ... - SVC close may block forever (waiting for atmsigd) - - polled devices are broken as designed (and will eventually go away ...) + - polled devices are broken as designed (and may eventually go away ...) - some system calls don't return full SVC SAP information - poor integration with other network code @@ -76,4 +78,4 @@ - there are lots of known bugs not listed in this file (look for @@@ in the source) - - there are still no "nice" applications + - there are *still* no "nice" applications diff -ur --new-file old/atm/CHANGES new/atm/CHANGES --- old/atm/CHANGES Mon Sep 9 19:42:24 1996 +++ new/atm/CHANGES Fri Sep 27 22:09:22 1996 @@ -1,3 +1,71 @@ +Version 0.18 to 0.19 (27-SEP-1996) +==================== + +Bug fixes +--------- + + - sscop.c:data_sd had a comparison inversed, so generation of USTAT PDUs was + wrong in some cases (by Juhana Rasanen) + - sigd_enq: accessed vcc->qos without checking for vcc == NULL, causing an + "Oops" in atmaddr + - svc_accept: generated a general protection fault when atmsigd was killed + while a process was waiting for new incoming connections + - atmaddr didn't zero the address structure before calling text2atm + - LANE: fixed usage of kernel timers and LE_ARP_REQUESTs should now get sent + until the entry expires or a response is received (by Marko Kiiskila) + - less compiler warnings from LANE servers (Marko Kiiskila) + - SSCOP: fixed SDU size in AA-RETRIEVE.indication (reported by Heinz Schuerch) + - NULL encapsulation for ATMARP works now (reported by Gerald Hanusch) + - fixed stray EINVAL from get{sock,peer}name on PVCs (reported by Gerald + Hanusch) + - clip now sets max_sdu to RFC1626_MTU+RFC1483LLC_LEN when using LLC/SNAP + encapsulation + - if parsing of a Q.2931 message fails, atmsigd now aborts the call instead of + (stupidly) trying to process the incomplete and probably inconsistent data + - SUNI driver didn't properly mask out unused highest bits of some statistics + counters, thereby yielding absurdly high values + - zatm: changed timing of RX channel closing, so the dreaded "can't close RX + channel" message should be history + - fixed race between Arequipa attachment due to packet reception and closing + of the Arequipa VC + - local address validity check (for ATM_???ADDR) was all wrong (reported by + David Simpson) + - message dumper ignored fatal errors if debugging was not enabled + +New features +------------ + + - man pages for lecs, les, bus, and zeppelin (Marko Kiiskila) + - configuration file name for les and bus can be defined (Marko Kiiskila) + - zatm: new kernel configuration option CONFIG_ATM_ZATM_EXACT_TS now supports + reception timestamps with microsecond resolution (the accuracy is only in + the ms range, though) + - new utility znth (ZeitNet Timer History) to monitor timer synchronization + - LANE now supports up to 4 LEC network interfaces (Marko Kiiskila) + - the Q.2931 message parser now recovers nicely from IE errors, logs the + event, and continues parsing. The higher layers of the signaling stack + don't use this information yet, though. + +Other changes +------------- + + - Arequipa's BHLI now uses a "vendor-specific application identifier" under + the EPFL OUI + - moved buffer/queue handling from lib/libatmd to saal/, because it is rather + SSCOP-specific anyway + - eni and zatm drivers now complain if rx_inuse != 0 when closing (if this + ever happens, it may point out dangerous races with upper layer protocols) + - SO_ATMQOS now issues a warning when using UBR with {min,max}_pcr != 0 + - max_sdu is now set by atmarpd to MTU+RFC1483LLC_LEN (atmarp could still + override this, if necessary) + - atmdump: new option -i to display the arrival interval interval instead + of the absolute time. Also changed to time format to be more readable. + - updated the kernel configuration documentation to indicate that the SMC + ATM Power155 adapters are compatible with the Efficient ENI-155 + - atmarpd now deletes the old table file (containing stale information) if + invoked with -d (debug) + + Version 0.17 to 0.18 (9-SEP-1996) ==================== diff -ur --new-file old/atm/CREDITS new/atm/CREDITS --- old/atm/CREDITS Wed Jun 5 19:33:54 1996 +++ new/atm/CREDITS Thu Sep 12 16:19:06 1996 @@ -13,8 +13,9 @@ Michael Ginis created the "ATM on Linux" logo using POV-Ray. -Marko Kiiskila contributed the LAN Emulation client (kernel code and a -demon process) and also found countless bugs in the signaling code. +Marko Kiiskila contributed LAN Emulation client and servers (kernel code +and demon processes), the ATM Name Service (ANS) programs, and also found +countless bugs in the signaling code. Ronald A. McCormick modularized the ATMTCP driver and also contributed a patch to upgrade from 1.3.24 to 1.3.50. diff -ur --new-file old/atm/README new/atm/README --- old/atm/README Mon Sep 9 20:17:30 1996 +++ new/atm/README Fri Sep 27 22:48:21 1996 @@ -1,4 +1,4 @@ -ATM on Linux, release 0.18 (pre-alpha) by Werner Almesberger, EPFL LRC +ATM on Linux, release 0.19 (pre-alpha) by Werner Almesberger, EPFL LRC ====================================== werner.almesberger@lrc.di.epfl.ch This is experimental software. There are known major bugs and certainly @@ -44,6 +44,8 @@ THIS SECTION IS OBSOLETE AND BADLY NEEDS TO BE UPDATED. ALSO NOTE THAT MOST OF THE THROUGHPUT MEASUREMENTS ARE TOO LOW BY 5% BECAUSE OF A BUG IN TTCP THAT WAS ONLY RECENTLY DISCOVERED. + +- - - - - - - - - - - - - obsolete text follows - - - - - - - - - - - - - - Note that version 0.10 has some debugging code enabled in the ENI driver. It is therefore about 10% slower than indicated below. diff -ur --new-file old/atm/USAGE new/atm/USAGE --- old/atm/USAGE Mon Sep 9 20:19:42 1996 +++ new/atm/USAGE Fri Sep 27 23:02:47 1996 @@ -1,4 +1,4 @@ -Usage instructions - ATM on Linux, release 0.18 (pre-alpha) +Usage instructions - ATM on Linux, release 0.19 (pre-alpha) ------------------------------------------------------------- For updates of ATM on Linux, please check the Web page at @@ -60,7 +60,7 @@ atm/led/ LAN Emulation demon: led atm/lane/ LAN Emulation servers: bus, lecs, les atm/aqd/ Arequipa demon: arequipad - atm/debug/ Debugging tools: ed, en, encopy, endump, and zndump + atm/debug/ Debugging tools: ed, en, encopy, endump, zndump, and znth atm/lib/ Libraries for applications and demons atm/doc/ Documentation in LaTeX and conversion tools @@ -83,6 +83,7 @@ Enable extended debugging (CONFIG_ATM_ENI_DEBUG) ZeitNet ZN1221/ZN1225 (CONFIG_ATM_ZATM) Enable extended debugging (CONFIG_ATM_ZATM_DEBUG) + Enable usec resolution timestamps (CONFIG_ATM_ZATM_EXACT_TS) Rolfs TI TNETA1570 (CONFIG_ATM_TNETA1570) Enable extended debugging (CONFIG_ATM_TNETA1570_DEBUG) diff -ur --new-file old/atm/VERSION new/atm/VERSION --- old/atm/VERSION Wed Sep 4 19:58:57 1996 +++ new/atm/VERSION Thu Sep 26 19:26:36 1996 @@ -1 +1 @@ -0.18 +0.19 diff -ur --new-file old/atm/aqd/io.c new/atm/aqd/io.c --- old/atm/aqd/io.c Sat Aug 31 14:16:22 1996 +++ new/atm/aqd/io.c Fri Sep 27 22:20:14 1996 @@ -50,9 +50,9 @@ diag(COMPONENT,DIAG_FATAL,"setsockopt SO_ATMQOS: %s",strerror(errno)); memset(&addr,0,sizeof(addr)); addr.sas_family = AF_ATMSVC; - addr.sas_addr.bhli.hl_type = ATM_HL_USER; - addr.sas_addr.bhli.hl_length = strlen("AREQ"); - strcpy(addr.sas_addr.bhli.hl_info,"AREQ"); + addr.sas_addr.bhli.hl_type = ATM_HL_VENDOR; + addr.sas_addr.bhli.hl_length = 7; + memcpy(addr.sas_addr.bhli.hl_info,AREQUIPA_HLT_VS_ID,7); addr.sas_addr.blli = &blli; blli.l2_proto = ATM_L2_ISO8802; blli.l3_proto = ATM_L3_NONE; diff -ur --new-file old/atm/arpd/arp.c new/atm/arpd/arp.c --- old/atm/arpd/arp.c Mon Sep 2 18:51:51 1996 +++ new/atm/arpd/arp.c Thu Sep 26 20:53:01 1996 @@ -450,6 +450,7 @@ } else { entry = alloc_entry(1); + entry->flags = ATF_PUBL; if (vcc) { vcc->entry = entry; Q_INSERT_HEAD(entry->vccs,vcc); @@ -531,6 +532,7 @@ } else { entry = alloc_entry(1); + entry->flags = ATF_PUBL; entry->ip = ip; entry->itf = itf; Q_INSERT_HEAD(itf->table,entry); @@ -644,8 +646,9 @@ entry = NULL; itf = lookup_itf_by_ip(tgt_ip); entry = itf ? lookup_ip(itf,tgt_ip) : NULL; - if (!entry) arp_nak(vcc,tgt_ip,src_ip,&source); - else arp_reply(vcc,tgt_ip,entry->addr,src_ip,&source); + if (entry && entry->state == as_valid && (entry->flags & ATF_PUBL)) + arp_reply(vcc,tgt_ip,entry->addr,src_ip,&source); + else arp_nak(vcc,tgt_ip,src_ip,&source); break; case ARPOP_REPLY: diag(COMPONENT,DIAG_DEBUG,"got ARP_REP"); @@ -766,6 +769,15 @@ } +static void adjust_qos(ITF *itf,struct atm_qos *qos,int null_encap) +{ + if (!qos->txtp.max_sdu) + qos->txtp.max_sdu = RFC1626_MTU+(null_encap ? 0 : RFC1483LLC_LEN); + if (!qos->rxtp.max_sdu) + qos->rxtp.max_sdu = RFC1626_MTU+(null_encap ? 0 : RFC1483LLC_LEN); +} + + int arp_ioctl(int itf_num,unsigned long cmd,struct atmarpreq *req) { ITF *itf; @@ -775,7 +787,7 @@ diag(COMPONENT,DIAG_DEBUG,"arp_ioctl 0x%08lx",cmd); if (req->arp_pa.sa_family != AF_INET) { - diag(COMPONENT,DIAG_ERROR,"SIOCSARP: bad PA AF 0x%x", + diag(COMPONENT,DIAG_ERROR,"SIOCxARP: bad PA AF 0x%x", req->arp_pa.sa_family); return -EPFNOSUPPORT; } @@ -797,10 +809,12 @@ req->arp_flags); switch (req->arp_ha.sas_family) { case AF_ATMPVC: + adjust_qos(itf,&req->arp_qos,req->arp_flags & ATF_NULL); return ioctl_set_pvc(itf,((struct sockaddr_in *) &req->arp_pa)->sin_addr.s_addr,(struct sockaddr_atmpvc *) &req->arp_ha,&req->arp_qos,req->arp_flags); case AF_ATMSVC: + adjust_qos(itf,&req->arp_qos,0); return ioctl_set_svc(itf,((struct sockaddr_in *) &req->arp_pa)->sin_addr.s_addr,(struct sockaddr_atmsvc *) &req->arp_ha,&req->arp_qos,req->arp_flags); diff -ur --new-file old/atm/arpd/atmarpd.c new/atm/arpd/atmarpd.c --- old/atm/arpd/atmarpd.c Mon Sep 2 15:31:58 1996 +++ new/atm/arpd/atmarpd.c Thu Sep 26 21:24:39 1996 @@ -84,6 +84,7 @@ diag(COMPONENT,DIAG_INFO,"Linux ATM ARP, version " VERSION); if (chdir(dump_dir) < 0) diag(COMPONENT,DIAG_ERROR,"chdir %s: %s",dump_dir,strerror(errno)); + if (debug) (void) unlink(TMP_DUMP_FILE); /* avoid confusion */ open_all(); if (background) { pid_t pid; diff -ur --new-file old/atm/arpd/io.c new/atm/arpd/io.c --- old/atm/arpd/io.c Mon Sep 2 18:28:50 1996 +++ new/atm/arpd/io.c Thu Sep 26 16:50:36 1996 @@ -417,7 +417,7 @@ } -int ip_itf_info(int number,unsigned long *ip,unsigned long *netmask) +int ip_itf_info(int number,unsigned long *ip,unsigned long *netmask,int *mtu) { struct ifreq req; unsigned char *p1,*p2; @@ -434,10 +434,15 @@ } *netmask = ((struct sockaddr_in *) &req.ifr_ifru.ifru_netmask)-> sin_addr.s_addr; + if (ioctl(inet,SIOCGIFMTU,&req) < 0) { + diag(COMPONENT,DIAG_ERROR,"ioctl SIOCGIFMTU: %s",strerror(errno)); + return -1; + } + *mtu = req.ifr_ifru.ifru_mtu; p1 = (unsigned char *) ip; p2 = (unsigned char *) netmask; - diag(COMPONENT,DIAG_DEBUG,"ip %d.%d.%d.%d mask %d.%d.%d.%d", - p1[0],p1[1],p1[2],p1[3],p2[0],p2[1],p2[2],p2[3]); + diag(COMPONENT,DIAG_DEBUG,"ip %d.%d.%d.%d mask %d.%d.%d.%d mtu %d", + p1[0],p1[1],p1[2],p1[3],p2[0],p2[1],p2[2],p2[3],*mtu); return 0; } diff -ur --new-file old/atm/arpd/io.h new/atm/arpd/io.h --- old/atm/arpd/io.h Mon Jun 10 19:33:18 1996 +++ new/atm/arpd/io.h Thu Sep 26 16:47:02 1996 @@ -18,7 +18,7 @@ int set_ip(int fd,int ip); int set_encap(int fd,int mode); void send_packet(int fd,void *data,int length); -int ip_itf_info(int number,unsigned long *ip,unsigned long *netmask); +int ip_itf_info(int number,unsigned long *ip,unsigned long *netmask,int *mtu); int get_local(int fd,struct sockaddr_atmsvc *addr); #endif diff -ur --new-file old/atm/arpd/itf.c new/atm/arpd/itf.c --- old/atm/arpd/itf.c Fri Jul 12 14:47:22 1996 +++ new/atm/arpd/itf.c Thu Sep 26 16:46:49 1996 @@ -55,7 +55,7 @@ return; } itf = alloc_t(ITF); - if (ip_itf_info(number,&itf->local_ip,&itf->netmask) < 0) { + if (ip_itf_info(number,&itf->local_ip,&itf->netmask,&itf->mtu) < 0) { free(itf); return; } diff -ur --new-file old/atm/arpd/table.c new/atm/arpd/table.c --- old/atm/arpd/table.c Thu Jul 18 20:15:59 1996 +++ new/atm/arpd/table.c Thu Sep 26 20:39:29 1996 @@ -109,10 +109,14 @@ static void dump_entries(ENTRY *list) { + static const char *flag_name[] = { "???","com","PERM","PUBL","trailers", + "netmask","NULL","ARPSRV" }; /* lower case flags are not used by ATMARP */ ENTRY *entry; VCC *vcc; char buffer[MAX_ATM_ADDR_LEN+1]; + char tmp[100]; /* large enough for all flags */ unsigned char *ipp; + int i; for (entry = list; entry ; entry = entry->next) { if (!entry->addr) strcpy(buffer,""); @@ -120,8 +124,15 @@ (struct sockaddr *) entry->addr,pretty) < 0) strcpy(buffer,""); ipp = (unsigned char *) &entry->ip; - output("IP %d.%d.%d.%d, state %s, addr %s, flags 0x%x",ipp[0],ipp[1], - ipp[2],ipp[3],entry_state_name[entry->state],buffer,entry->flags); + *tmp = 0; + for (i = 0; i < 8; i++) + if (entry->flags & (1 << i)) { + if (*tmp) strcat(tmp,","); + strcat(tmp,flag_name[i]); + } + output("IP %d.%d.%d.%d, state %s, addr %s, flags 0x%x<%s>",ipp[0], + ipp[1],ipp[2],ipp[3],entry_state_name[entry->state],buffer, + entry->flags,tmp); for (vcc = entry->vccs; vcc; vcc = vcc->next) dump_vcc(vcc); } } diff -ur --new-file old/atm/arpd/table.h new/atm/arpd/table.h --- old/atm/arpd/table.h Thu Jul 18 20:15:56 1996 +++ new/atm/arpd/table.h Thu Sep 26 16:46:22 1996 @@ -50,6 +50,7 @@ unsigned long local_ip; /* @@@ */ unsigned long netmask; int number; + int mtu; ENTRY *table; ENTRY *arp_srv; /* NULL is none */ struct _itf *prev,*next; diff -ur --new-file old/atm/atm.patch new/atm/atm.patch --- old/atm/atm.patch Mon Sep 9 20:37:01 1996 +++ new/atm/atm.patch Fri Sep 27 23:25:01 1996 @@ -20,8 +20,8 @@ ls *.o > .allmods; \ echo $$MODULES | tr ' ' '\n' | sort | comm -23 .allmods - > .misc; \ --- ref/Documentation/Configure.help Wed Aug 7 08:45:41 1996 -+++ work/Documentation/Configure.help Wed Aug 21 10:55:34 1996 -@@ -1182,6 +1182,101 @@ ++++ work/Documentation/Configure.help Thu Sep 26 19:32:46 1996 +@@ -1182,6 +1182,111 @@ you can read some network related routing information from that file. Everything you write to that file will be discarded. @@ -80,10 +80,11 @@ + +Efficient Networks ENI155P +CONFIG_ATM_ENI -+ Driver for the Efficient Networks ENI155p series 155 Mbps ATM adapters. -+ Both, the C and S variants (512kB and 2MB ob-board RAM, respectively), -+ and the FPGA and the ASIC Tonga versions of the board are supported. -+ The driver works with MMF (-MF) and UTP-5 (-U5) adapters. ++ 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 @@ -106,6 +107,15 @@ + 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 155 Mbps ATM adapter, both developed by Rolf @@ -215,9 +225,9 @@ endif ifeq ($(CONFIG_AP1000),y) ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/drivers/atm/Config.in Wed Aug 21 10:55:36 1996 -@@ -0,0 +1,21 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/drivers/atm/Config.in Thu Sep 26 18:58:10 1996 +@@ -0,0 +1,22 @@ +# +# ATM device configuration +# @@ -233,6 +243,7 @@ + tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM y + if [ ! "$CONFIG_ATM_ZATM" = "n" ]; then + bool ' Enable extended debugging' CONFIG_ATM_ZATM_DEBUG n ++ bool ' Enable usec resolution timestamps' CONFIG_ATM_ZATM_EXACT_TS y + fi + bool 'Rolfs TI TNETA1570' CONFIG_ATM_TNETA1570 y + if [ "$CONFIG_ATM_TNETA1570" = "y" ]; then @@ -259,7 +270,7 @@ + bool ' LANE support' CONFIG_ATM_LANE y +fi endmenu ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/drivers/atm/Makefile Thu Aug 29 13:50:20 1996 @@ -0,0 +1,47 @@ +# File: drivers/atm/Makefile @@ -309,7 +320,7 @@ +EXTRA_CFLAGS=-g + +include $(TOPDIR)/Rules.make ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/drivers/atm/atmdev_init.c Wed Aug 21 10:55:36 1996 @@ -0,0 +1,47 @@ +/* drivers/atm/atmdev_init.c - ATM device driver initialization */ @@ -359,7 +370,7 @@ +#endif + return devs; +} ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/drivers/atm/atmtcp.c Wed Aug 21 10:55:37 1996 @@ -0,0 +1,316 @@ +/* drivers/atm/atmtcp.c - ATM over TCP "device" driver */ @@ -678,9 +689,9 @@ +} + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/drivers/atm/eni.c Thu Aug 29 13:41:36 1996 -@@ -0,0 +1,1954 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/drivers/atm/eni.c Fri Sep 27 16:16:48 1996 +@@ -0,0 +1,1949 @@ +/* drivers/atm/eni.c - Efficient Networks ENI155P device driver */ + +/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ @@ -2395,13 +2406,8 @@ + EVENT("eni_open\n",0,0); + if (!(vcc->flags & ATM_VF_PARTIAL)) ENI_VCC(vcc) = NULL; + eni_dev = ENI_DEV(vcc->dev); -+#if 1 /* set to 0 to test atm_find_ci (get_ci usually is faster) */ + error = get_ci(vcc,&vpi,&vci); + if (error) return error; -+#else -+ error = atm_find_ci(vcc,&vpi,&vci); -+ if (error) return error; -+#endif + vcc->vpi = vpi; + vcc->vci = vci; + if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC) @@ -2635,8 +2641,8 @@ +} + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/drivers/atm/eni.h Mon Sep 9 18:53:03 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/drivers/atm/eni.h Fri Sep 27 15:21:16 1996 @@ -0,0 +1,113 @@ +/* drivers/atm/eni.h - Efficient Networks ENI155P device driver declarations */ + @@ -2751,7 +2757,7 @@ +#endif /* __KERNEL__ */ + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/drivers/atm/midway.h Wed Aug 21 10:55:38 1996 @@ -0,0 +1,265 @@ +/* drivers/atm/midway.h - Efficient Networks Midway (SAR) description */ @@ -3019,8 +3025,8 @@ +#define MID_DT_HWORD 0x2 + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/drivers/atm/suni.c Thu Aug 29 15:21:02 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/drivers/atm/suni.c Thu Sep 26 22:48:49 1996 @@ -0,0 +1,298 @@ +/* drivers/atm/suni.c - PMC SUNI (PHY) driver */ + @@ -3088,14 +3094,14 @@ + if (stats->section_bip < 0) stats->section_bip = LONG_MAX; + stats->line_bip += (GET(RLOP_LBL) & 0xff) | + ((GET(RLOP_LB) & 0xff) << 8) | -+ ((GET(RLOP_LBM) & 0xff) << 16); ++ ((GET(RLOP_LBM) & 0xf) << 16); + if (stats->line_bip < 0) stats->line_bip = LONG_MAX; + stats->path_bip += (GET(RPOP_PBL) & 0xff) | + ((GET(RPOP_PBM) & 0xff) << 8); + if (stats->path_bip < 0) stats->path_bip = LONG_MAX; + stats->line_febe += (GET(RLOP_LFL) & 0xff) | + ((GET(RLOP_LF) & 0xff) << 8) | -+ ((GET(RLOP_LFM) & 0xff) << 16); ++ ((GET(RLOP_LFM) & 0xf) << 16); + if (stats->line_febe < 0) stats->line_febe = LONG_MAX; + stats->path_febe += (GET(RPOP_PFL) & 0xff) | + ((GET(RPOP_PFM) & 0xff) << 8); @@ -3106,11 +3112,11 @@ + if (stats->uncorr_hcs < 0) stats->uncorr_hcs = LONG_MAX; + stats->rx_cells += (GET(RACP_RCCL) & 0xff) | + ((GET(RACP_RCC) & 0xff) << 8) | -+ ((GET(RACP_RCCM) & 0xff) << 16); ++ ((GET(RACP_RCCM) & 7) << 16); + if (stats->rx_cells < 0) stats->rx_cells = LONG_MAX; + stats->tx_cells += (GET(TACP_TCCL) & 0xff) | + ((GET(TACP_TCC) & 0xff) << 8) | -+ ((GET(TACP_TCCM) & 0xff) << 16); ++ ((GET(TACP_TCCM) & 7) << 16); + if (stats->tx_cells < 0) stats->tx_cells = LONG_MAX; + } + if (!start_timer) { @@ -3320,8 +3326,8 @@ +} + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/drivers/atm/suni.h Mon Sep 9 18:53:03 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/drivers/atm/suni.h Fri Sep 27 15:21:16 1996 @@ -0,0 +1,219 @@ +/* drivers/atm/suni.h - PMC SUNI (PHY) declarations */ + @@ -3542,7 +3548,7 @@ +#endif + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/drivers/atm/tonga.h Wed Aug 21 10:55:39 1996 @@ -0,0 +1,20 @@ +/* drivers/atm/tonga.h - Efficient Networks Tonga (PCI bridge) declarations */ @@ -3565,7 +3571,7 @@ +#define SEPROM_ESI_BASE 64 /* start of ESI in serial EEPROM */ + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/drivers/atm/uPD98401.h Wed Aug 21 10:55:39 1996 @@ -0,0 +1,292 @@ +/* drivers/atm/uPD98401.h - NEC uPD98401 (SAR) declarations */ @@ -3860,7 +3866,7 @@ +#define uPD98401_RXLT_ENBL 0x8000 /* Enable */ + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/drivers/atm/uPD98402.h Wed Aug 21 10:55:39 1996 @@ -0,0 +1,106 @@ +/* drivers/atm/uPD98402.h - NEC uPD98402 (PHY) declarations */ @@ -3969,7 +3975,7 @@ +int uPD98402_init(struct atm_dev *dev); + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/drivers/atm/uPD98402.c Thu Aug 29 15:19:33 1996 @@ -0,0 +1,228 @@ +/* drivers/atm/uPD98402.c - NEC uPD98402 (PHY) declarations */ @@ -4200,9 +4206,9 @@ +} + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/drivers/atm/zatm.c Thu Aug 29 13:41:42 1996 -@@ -0,0 +1,1659 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/drivers/atm/zatm.c Fri Sep 27 14:25:13 1996 +@@ -0,0 +1,1841 @@ +/* drivers/atm/zatm.c - ZeitNet ZN122x device driver */ + +/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ @@ -4320,9 +4326,9 @@ +static unsigned long dummy[2] = {0,0}; + + -+#define zin_n(r) inl_p(zatm_dev->base+r*4) -+#define zin(r) inl_p(zatm_dev->base+uPD98401_##r*4) -+#define zout(v,r) outl_p(v,zatm_dev->base+uPD98401_##r*4) ++#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 */ @@ -4531,6 +4537,150 @@ +} + + ++/*----------------------- high-precision timestamps -------------------------*/ ++ ++ ++#ifdef CONFIG_ATM_ZATM_EXACT_TS ++ ++static struct timer_list sync_timer = { NULL, NULL, 0L, 0L, NULL }; ++ ++ ++/* ++ * Note: the exact time is not normalized, i.e. tv_usec can be > 1000000. ++ * This must be handled by higher layers. ++ */ ++ ++static inline struct timeval exact_time(struct zatm_dev *zatm_dev,u32 ticks) ++{ ++ struct timeval tmp; ++ ++ tmp = zatm_dev->last_time; ++ tmp.tv_usec += ((s64) (ticks-zatm_dev->last_clk)* ++ (s64) zatm_dev->factor) >> TIMER_SHIFT; ++ return tmp; ++} ++ ++ ++static void zatm_clock_sync(unsigned long dummy) ++{ ++ struct atm_dev *atm_dev; ++ struct zatm_dev *zatm_dev; ++ ++ for (atm_dev = zatm_boards; atm_dev; atm_dev = zatm_dev->more) { ++ unsigned long flags,interval; ++ int diff; ++ struct timeval now,expected; ++ u32 ticks; ++ ++ 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); ++#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; ++ ++ 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); ++} ++ ++ ++#endif ++ ++ +/*----------------------------------- RX ------------------------------------*/ + + @@ -4621,7 +4771,11 @@ +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], @@ -4784,7 +4938,7 @@ + zatm_vcc = ZATM_VCC(vcc); + zatm_dev = ZATM_DEV(vcc->dev); + if (!zatm_vcc->rx_chan) return; -+DPRINTK("close_rx\n"); ++ DPRINTK("close_rx\n"); + /* disable receiver */ + save_flags(flags); + if (vcc->vpi != ATM_VPI_UNSPEC && vcc->vci != ATM_VCI_UNSPEC) { @@ -4792,14 +4946,18 @@ + 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); -+ udelay(48000/zatm_dev->khz+1); + } + 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; @@ -5451,18 +5609,26 @@ + for (i = 0; i < ESI_LEN; i++) + printk("%02X%s",dev->esi[i],i == ESI_LEN-1 ? ")\n" : "-"); + do { ++ unsigned long flags; ++ ++ 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); ++ 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); ++#endif + return uPD98402_init(dev); +} + @@ -5680,6 +5846,28 @@ + restore_flags(flags); + return 0; + } ++#ifdef CONFIG_ATM_ZATM_EXACT_TS ++ case ZATM_GETTHIST: ++ { ++ int i; ++ ++ 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); @@ -5862,9 +6050,9 @@ +} + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/drivers/atm/zatm.h Mon Sep 9 18:53:32 1996 -@@ -0,0 +1,128 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/drivers/atm/zatm.h Fri Sep 27 15:21:47 1996 +@@ -0,0 +1,172 @@ +/* drivers/atm/zatm.h - ZeitNet ZN122x device driver declarations */ + +/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ @@ -5873,6 +6061,11 @@ +#ifndef DRIVER_ATM_ZATM_H +#define DRIVER_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) @@ -5881,7 +6074,9 @@ + /* 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 */ @@ -5896,12 +6091,19 @@ + 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 */ + + +#ifdef __KERNEL__ @@ -5939,6 +6141,25 @@ +#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 */ @@ -5977,6 +6198,17 @@ + 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 */ @@ -5993,7 +6225,7 @@ + +#endif __KERNEL__ +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/drivers/atm/zeprom.h Wed Aug 21 10:55:41 1996 @@ -0,0 +1,34 @@ +/* drivers/atm/zeprom.h - ZeitNet ZN122x EEPROM (NM93C46) declarations */ @@ -6030,7 +6262,7 @@ +/* No other commands are needed. */ + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/drivers/atm/tneta1570.h Wed Aug 21 10:55:41 1996 @@ -0,0 +1,310 @@ +/* drivers/atm/tneta1570.h - TI TNETA1570 (SAR) declarations */ @@ -6343,7 +6575,7 @@ + +#endif __KERNEL__ +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/drivers/atm/tneta1570.c Wed Aug 21 10:55:42 1996 @@ -0,0 +1,1479 @@ +/* drivers/atm/tneta1570.c - ti tneta1570 atm driver */ @@ -7825,7 +8057,7 @@ + } + return index; +} ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/drivers/atm/fore200.c Wed Aug 21 10:55:43 1996 @@ -0,0 +1,26 @@ +/* drivers/atm/fore200.c - This is just a test, not a real driver */ @@ -7854,7 +8086,7 @@ + } + return 0; +} ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/include/linux/atm.h Mon Sep 2 11:44:50 1996 @@ -0,0 +1,217 @@ +/* atm.h - general ATM declarations */ @@ -8074,8 +8306,8 @@ +#endif /* __KERNEL__ */ + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/include/linux/atmclip.h Mon Sep 9 18:58:20 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/atmclip.h Fri Sep 27 15:23:43 1996 @@ -0,0 +1,37 @@ +/* atmclip.h - Classical IP over ATM */ + @@ -8114,9 +8346,9 @@ +#endif /* __KERNEL__ */ + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/include/linux/atmdev.h Mon Sep 9 18:45:07 1996 -@@ -0,0 +1,242 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/atmdev.h Fri Sep 27 15:20:29 1996 +@@ -0,0 +1,245 @@ +/* atmdev.h - ATM device driver declarations */ + +/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ @@ -8237,6 +8469,7 @@ + traffic and doesn't depend on signaling + to be available */ +#define ATM_VF_AQREL 256 /* Arequipa socket is being released */ ++#define ATM_VF_AQINUSE 512 /* socket is available for Arequipa use */ + +struct atm_vcc { + unsigned short flags; /* VCC flags (ATM_VF_*) */ @@ -8282,6 +8515,8 @@ +#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 +}; + @@ -8359,7 +8594,7 @@ +#endif /* __KERNEL__ */ + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/include/linux/atmsap.h Wed Aug 21 10:55:44 1996 @@ -0,0 +1,129 @@ +/* atmsap.h - ATM Service Access Point addressing definitions */ @@ -8492,8 +8727,8 @@ + +#endif --- ref/include/linux/skbuff.h Tue Aug 20 17:09:42 1996 -+++ work/include/linux/skbuff.h Mon Sep 9 18:45:07 1996 -@@ -112,6 +112,16 @@ ++++ work/include/linux/skbuff.h Fri Sep 27 14:37:42 1996 +@@ -112,6 +112,21 @@ unsigned char *end; /* End pointer */ void (*destructor)(struct sk_buff *); /* Destruct function */ __u16 redirport; /* Redirect port */ @@ -8503,14 +8738,19 @@ + unsigned long pos; /* adapter data */ + struct atm_vcc *vcc; /* ATM VCC */ + int iovcnt; /* 0 for "normal" operation */ -+ struct timeval timestamp; /* timestamp or 0 */ ++ struct timeval timestamp; /* timestamp or 0,x */ ++ 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 Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/include/linux/sonet.h Wed Aug 21 10:55:45 1996 @@ -0,0 +1,52 @@ +/* sonet.h - SONET/SHD physical layer control */ @@ -8565,7 +8805,7 @@ +#define SONET_FRSENSE_SIZE 6 /* C1[3],H1[3] (0xff for unknown) */ + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/include/linux/atmsvc.h Wed Sep 4 15:32:45 1996 @@ -0,0 +1,51 @@ +/* atmsvc.h - ATM signaling kernel-demon interface definitions */ @@ -8619,7 +8859,7 @@ + (tp).max_pcr : (tp).min_pcr) + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/include/linux/atmioc.h Wed Aug 21 10:55:45 1996 @@ -0,0 +1,32 @@ +/* atmioc.h - ranges for ATM-related ioctl numbers */ @@ -8677,7 +8917,7 @@ endif ifeq ($(CONFIG_INET),y) ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/net/atm/Makefile Wed Aug 21 10:55:46 1996 @@ -0,0 +1,54 @@ +# @@ -8734,7 +8974,7 @@ + + +include $(TOPDIR)/Rules.make ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/net/atm/clip.c Mon Sep 9 14:04:35 1996 @@ -0,0 +1,116 @@ +/* net/atm/clip.c - Classical IP over ATM */ @@ -8853,9 +9093,9 @@ + DPRINTK("registered %s,0x%lx\n",dev->name,(unsigned long) vcc); + return CLIP(dev)->number; +} ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/common.c Sat Aug 31 14:34:48 1996 -@@ -0,0 +1,900 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/common.c Thu Sep 26 23:16:16 1996 +@@ -0,0 +1,919 @@ +/* net/atm/common.c - ATM sockets (common part for PVC and SVC) */ + +/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ @@ -8979,8 +9219,13 @@ + 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))) ++ while ((skb = skb_dequeue(&vcc->recvq))) { ++ atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->rx_inuse); + 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; @@ -9448,6 +9693,9 @@ + } + case SIOCGSTAMP: /* borrowed from IP */ + if (!ATM_SD(sock)->timestamp.tv_sec) return -ENOENT; ++ ATM_SD(sock)->timestamp.tv_sec += ++ ATM_SD(sock)->timestamp.tv_usec/1000000; ++ ATM_SD(sock)->timestamp.tv_usec %= 1000000; + error = verify_area(VERIFY_WRITE,(void *) arg, + sizeof(struct timeval)); + if (error) return error; @@ -9515,12 +9763,12 @@ +#ifdef CONFIG_ATM_LANE + case ATMLEC_CTRL: + if (!suser()) return -EPERM; -+ error = lecd_attach(ATM_SD(sock)); -+ if (!error) sock->state = SS_CONNECTED; ++ error = lecd_attach(ATM_SD(sock), (int)arg); ++ if (error >=0) sock->state = SS_CONNECTED; + return error; + case ATMLEC_MCAST: + if (!suser()) return -EPERM; -+ return lec_mcast_attach(ATM_SD(sock)); ++ return lec_mcast_attach(ATM_SD(sock), (int)arg); + case ATMLEC_DATA: + if (!suser()) return -EPERM; + return lec_vcc_attach(ATM_SD(sock), (void*)arg); @@ -9674,6 +9922,17 @@ + if (optlen != sizeof(struct atm_qos)) + return -EINVAL; + memcpy_fromfs(&vcc->qos,optval,optlen); ++ 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 will change " ++ "with min/max_pcr != 0\n"); + vcc->flags |= ATM_VF_HASQOS; + return 0; + default: @@ -9756,7 +10015,7 @@ + if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL; + return vcc->dev->ops->getsockopt(vcc,level,optname,optval,optlen); +} ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/net/atm/common.h Wed Aug 21 10:55:47 1996 @@ -0,0 +1,32 @@ +/* net/atm/common.h - ATM sockets (common part for PVC and SVC) */ @@ -9791,7 +10050,7 @@ +void svc_callback(struct atm_vcc *vcc); + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/net/atm/dev.c Wed Aug 21 10:55:47 1996 @@ -0,0 +1,38 @@ +/* net/atm/dev.c - ATM device registeration */ @@ -9832,9 +10091,9 @@ +{ + free_atm_dev(dev); +} ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/pvc.c Wed Aug 21 10:55:47 1996 -@@ -0,0 +1,162 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/pvc.c Thu Sep 26 14:30:53 1996 +@@ -0,0 +1,161 @@ +/* net/atm/pvc.c - ATM PVC sockets */ + +/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ @@ -9921,7 +10180,6 @@ +#if 0 /* add some sanity checks later ... @@@ */ + if (sock->state != SS_CONNECTED) return -EINVAL; +#endif -+ if (*sockaddr_len < sizeof(struct sockaddr_atmpvc)) return -EINVAL; + *sockaddr_len = sizeof(struct sockaddr_atmpvc); + addr = (struct sockaddr_atmpvc *) sockaddr; + vcc = ATM_SD(sock); @@ -9997,7 +10255,7 @@ + (void) atm_init_arequipa(); +#endif +} ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/net/atm/static.c Wed Aug 21 10:55:47 1996 @@ -0,0 +1,114 @@ +/* net/atm/static.c - Staticly allocated resources */ @@ -10114,8 +10372,8 @@ + for (i = 0; i < MAX_ATM_VCC; i++) + if (atm_vcc[i].family) fn(atm_vcc+i); +} ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/static.h Mon Sep 9 18:58:20 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/static.h Fri Sep 27 15:23:43 1996 @@ -0,0 +1,29 @@ +/* net/atm/static.h - Staticly allocated resources */ + @@ -10146,9 +10404,9 @@ +void for_all_vccs(void (*fn)(struct atm_vcc *vcc)); + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/svc.c Thu Sep 5 21:43:21 1996 -@@ -0,0 +1,601 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/svc.c Fri Sep 27 15:16:06 1996 +@@ -0,0 +1,600 @@ +/* net/atm/svc.c - ATM SVC sockets */ + +/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ @@ -10431,8 +10689,7 @@ + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + } -+ /* should try to atm_connect now and possibly send a close on -+ error */ ++ if (!skb) return -EUNATCH; + msg = (struct atmsvc_msg *) skb->data; + new_vcc->qos = msg->qos; + new_vcc->flags |= ATM_VF_HASQOS; @@ -10497,11 +10754,11 @@ + int i; + + if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT; -+ if (!*addr->sas_addr.prv) -+ if (!*addr->sas_addr.pub) return -EINVAL; ++ if (!*addr->sas_addr.pub) ++ if (!*addr->sas_addr.prv) return -EINVAL; + else return 0; -+ for (i = 1; i < ATM_E164_LEN+1; i++) -+ if (!addr->sas_addr.prv[i]) 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; +} + @@ -10750,8 +11007,8 @@ + return; + } +} ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/signaling.c Wed Sep 4 18:49:50 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/signaling.c Thu Sep 12 10:21:05 1996 @@ -0,0 +1,219 @@ +/* net/atm/signaling.c - ATM signaling */ + @@ -10875,7 +11132,7 @@ + msg->vcc = (unsigned long) vcc; + msg->listen_vcc = (unsigned long) listen_vcc; + msg->aal = vcc ? vcc->aal : 0; -+ msg->qos = vcc->qos; ++ if (vcc) msg->qos = vcc->qos; + if (!svc) msg->svc.sas_family = 0; + else { + msg->svc = *svc; @@ -10972,8 +11229,8 @@ + wake_up(&sigd_sleep); + return 0; +} ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/signaling.h Mon Sep 9 18:58:20 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/signaling.h Fri Sep 27 15:23:43 1996 @@ -0,0 +1,25 @@ +/* net/atm/signaling.h - ATM signaling */ + @@ -11000,9 +11257,9 @@ +int sigd_attach(struct atm_vcc *vcc); + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/atmarp.c Mon Sep 9 13:23:35 1996 -@@ -0,0 +1,600 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/atmarp.c Thu Sep 26 14:24:39 1996 +@@ -0,0 +1,604 @@ +/* atmarp.c - RFC1577 ATM ARP */ + +/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ @@ -11265,6 +11522,7 @@ + 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; +} + @@ -11314,9 +11572,12 @@ + /* Should return -EHOSTUNREACH, but then it will retry + forever, so we just discard the packet. */ + } -+ if (!entry->encap) skb_push(skb,RFC1483LLC_LEN); -+ /* assumes that we'll never attempt to xmit the same packet -+ twice @@@ */ ++ 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); @@ -11603,8 +11864,8 @@ + register_netdevice_notifier(&clip_dev_notifier); + return 0; +} ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/atmarp.h Mon Sep 9 18:58:20 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/atmarp.h Fri Sep 27 15:23:43 1996 @@ -0,0 +1,53 @@ +/* net/atm/atmarp.h - RFC1577 ATM ARP */ + @@ -11659,8 +11920,8 @@ +int atmarp_encap(struct atm_vcc *vcc,int mode); + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/ipcommon.h Mon Sep 9 18:59:12 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/ipcommon.h Fri Sep 27 15:24:41 1996 @@ -0,0 +1,73 @@ +/* net/atm/ipcommon.h - Common items for all ways of doing IP over ATM */ + @@ -11735,7 +11996,7 @@ +int ipcom_pick_number(int number); + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/net/atm/ipcommon.c Mon Sep 9 20:07:49 1996 @@ -0,0 +1,214 @@ +/* net/atm/ipcommon.c - Common items for all ways of doing IP over ATM */ @@ -11952,9 +12213,9 @@ + } + return number; +} ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/arequipa.c Wed Aug 21 10:55:50 1996 -@@ -0,0 +1,367 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/arequipa.c Fri Sep 27 18:29:03 1996 +@@ -0,0 +1,417 @@ +/* net/atm/arequipa.c - Application requested IP over ATM */ + +/* Written 1996 by Jean-Michel Pittet and Werner Almesberger, EPFL LRC */ @@ -12014,6 +12275,28 @@ +}; + + ++static struct atm_vcc *aq_list = NULL; ++static unsigned long aq_generation = 0; ++ ++ ++static void arequipa_unuse(struct atm_vcc *vcc) ++{ ++ unsigned long flags; ++ ++ save_flags(flags); ++ cli(); ++ if (!(vcc->flags & ATM_VF_AQINUSE)) { ++ restore_flags(flags); ++ return; ++ } ++ vcc->flags &= ~ATM_VF_AQINUSE; ++ 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 @@ -12054,6 +12337,7 @@ + if (!(lower = upper->arequipa)) return -ENOTCONN; + save_flags(flags); + cli(); ++ arequipa_unuse(ATM_SD(lower)); + upper->arequipa = NULL; + ATM_SD(lower)->upper = NULL; + if (!(ATM_SD(lower)->flags & ATM_VF_AQREL)) aqd_enq(ATM_SD(lower)); @@ -12065,10 +12349,13 @@ + +void arequipa_close_vcc(struct atm_vcc *vcc) +{ -+ if (!(vcc->flags & ATM_VF_AQREL)) ++ if (!(vcc->flags & ATM_VF_AQREL)) { + printk(KERN_CRIT "arequipa_close_3rd_party: VCC %p doesn't " + "have ATM_VF_AQREL set\n",vcc); -+ else close_fp(vcc->sock->file); ++ return; ++ } ++ arequipa_unuse(vcc); ++ close_fp(vcc->sock->file); +} + + @@ -12082,6 +12369,7 @@ + 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 " @@ -12116,6 +12404,7 @@ + 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); +} + @@ -12133,29 +12422,33 @@ + vcc->push = atm_push_arequipa; + vcc->peek = atm_peek_clip; + vcc->push_oam = NULL; ++ vcc->aq_next = aq_list; ++ vcc->aq_prev = NULL; ++ aq_list = vcc; ++ vcc->generation = aq_generation++; + restore_flags(flags); + lower->file->f_count++; +} + + -+int arequipa_attach(struct socket *lower,struct sock *upper) ++static int arequipa_attach_unchecked(struct socket *lower,struct sock *upper) +{ + struct rtable *rt; + int error; + + if (upper->arequipa) { -+ printk(KERN_WARNING "arequipa_attach: upper already uses " -+ "Arequipa\n"); ++ printk(KERN_WARNING "arequipa_attach_unchecked: upper already " ++ "uses Arequipa\n"); + return -EISCONN; + } + error = check_aq_vcc(lower); + if (error) return error; + if (ATM_SD(lower)->upper) { -+ printk(KERN_WARNING "arequipa_attach: lower is already " -+ "attached\n"); ++ printk(KERN_WARNING "arequipa_attach_unchecked: lower is " ++ "already attached\n"); + return -EISCONN; + } -+ DPRINTK("arequipa_attach %p (i_count=%d,f_count=%d)\n",upper, ++ 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; @@ -12166,6 +12459,24 @@ +} + + ++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); @@ -12196,7 +12507,7 @@ + } + error = arequipa_expect(upper,1); + if (error) return error; -+ error = arequipa_attach(lower,upper); ++ error = arequipa_attach_unchecked(lower,upper); + if (!error) make_aq_vcc(lower); + return error; +} @@ -12322,7 +12633,7 @@ + return 0; + +} ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/net/atm/tunable.h Wed Aug 21 10:55:50 1996 @@ -0,0 +1,26 @@ +/* net/atm/tunable.h - Tunable parameters of ATM support */ @@ -12434,7 +12745,7 @@ #endif { NULL, NULL } /* End marker */ }; ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/net/atm/mmuio.c Wed Aug 21 10:55:51 1996 @@ -0,0 +1,455 @@ +/* net/atm/mmuio.c - MMU-supported high-speed I/O */ @@ -12892,8 +13203,8 @@ +} + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/include/linux/mmuio.h Mon Sep 9 18:58:20 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/mmuio.h Fri Sep 27 15:23:43 1996 @@ -0,0 +1,25 @@ +/* mmuio.h - MMU-supported high-speed I/O */ + @@ -12920,7 +13231,7 @@ +#endif + +#endif ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/net/atm/raw.c Wed Aug 21 10:55:52 1996 @@ -0,0 +1,139 @@ +/* net/atm/raw.c - Raw AAL0 and AAL5 transports */ @@ -13062,7 +13373,7 @@ + vcc->push_oam = NULL; + return 0; +} ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/net/atm/protocols.h Wed Aug 21 10:55:52 1996 @@ -0,0 +1,17 @@ +/* net/atm/protocols.h - ATM protocol handler entry points */ @@ -13083,7 +13394,7 @@ + +#endif --- ref/include/linux/netdevice.h Tue Aug 20 17:11:35 1996 -+++ work/include/linux/netdevice.h Mon Sep 9 18:45:07 1996 ++++ work/include/linux/netdevice.h Fri Sep 27 15:20:29 1996 @@ -185,6 +185,8 @@ int (*set_mac_address)(struct device *dev, void *addr); #define HAVE_PRIVATE_IOCTL @@ -13102,7 +13413,7 @@ extern void tr_setup(struct device *dev); extern int ether_config(struct device *dev, struct ifmap *map); /* Support for loadable net-drivers */ ---- /dev/null Mon Sep 9 20:17:39 1996 +--- /dev/null Mon Jul 18 01:46:18 1994 +++ work/include/linux/atmarp.h Mon Sep 2 19:12:43 1996 @@ -0,0 +1,98 @@ +/* atmarp.h - ATM ARP protocol and kernel-demon interface definitions */ @@ -13204,7 +13515,7 @@ + +#endif --- ref/net/ipv4/udp.c Tue Jun 4 14:34:43 1996 -+++ work/net/ipv4/udp.c Wed Aug 21 10:55:53 1996 ++++ work/net/ipv4/udp.c Fri Sep 27 14:53:25 1996 @@ -109,6 +109,11 @@ #include #include @@ -13226,14 +13537,15 @@ return(0); } -@@ -655,6 +660,12 @@ +@@ -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); ++ (void) arequipa_attach(skb->atm.vcc->sock,sk, ++ skb->atm.generation); + } +#endif skb->sk = sk; @@ -13278,7 +13590,7 @@ /* Tell the sender its packet died... */ icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, dev); --- ref/include/linux/proc_fs.h Tue Aug 20 17:09:42 1996 -+++ work/include/linux/proc_fs.h Mon Sep 9 18:45:07 1996 ++++ work/include/linux/proc_fs.h Thu Sep 26 19:23:39 1996 @@ -34,6 +34,7 @@ PROC_KSYMS, PROC_DMA, @@ -13400,9 +13712,9 @@ case PROC_KCORE: inode->i_mode = S_IFREG | S_IRUSR; inode->i_op = &proc_kcore_inode_operations; ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/proc.c Mon Sep 9 14:02:17 1996 -@@ -0,0 +1,485 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/proc.c Thu Sep 26 22:12:08 1996 +@@ -0,0 +1,501 @@ +/* net/atm/proc.c - ATM /proc interface */ + +/* Written 1995,1996 by Werner Almesberger, EPFL LRC */ @@ -13431,10 +13743,9 @@ +#include "atmarp.h" + +#ifdef CONFIG_ATM_LANE ++#include "lec.h" +#include "lec_arpc.h" -+extern struct lec_arp_table *lec_arp_tables[LEC_ARP_TABLE_SIZE]; -+extern struct lec_arp_table *lec_arp_empty_ones; -+extern struct lec_arp_table *lec_no_forward; ++extern struct device *dev_lec[MAX_LEC_ITF]; +#endif + +#ifdef CONFIG_AREQUIPA @@ -13465,7 +13776,7 @@ + break; +#ifdef CONFIG_ATM_LANE + case PROC_ATM_LEC: -+ sprintf(buf," MAC ATM destination Status Flags VPI/VCI Recv VPI/VCI\n"); ++ sprintf(buf,"Itf MAC ATM destination Status Flags VPI/VCI Recv VPI/VCI\n"); + break; +#endif +#ifdef CONFIG_AREQUIPA @@ -13669,6 +13980,7 @@ + + +#ifdef CONFIG_ATM_LANE ++ +static char* +lec_arp_get_status_string(unsigned char status) +{ @@ -13706,8 +14018,9 @@ + entry->flags&0xffff); + if (entry->vcc) { + offset+=sprintf(buf+offset, "%3d %3d ", entry->vcc->vpi, -+ entry->vcc->vci); -+ } ++ 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); @@ -13715,6 +14028,7 @@ + + sprintf(buf+offset,"\n"); +} ++ +#endif + + @@ -13776,36 +14090,50 @@ + break; +#endif +#ifdef CONFIG_ATM_LANE -+ case PROC_ATM_LEC: -+ { -+ struct lec_arp_table *entry; -+ int i, count; -+ -+ count = *pos; -+ for(i=0;inext) { -+ if (!--count) { -+ lec_info(entry, buf); -+ return strlen(buf); -+ } -+ } -+ for(entry=lec_arp_empty_ones; -+ entry; entry=entry->next) { -+ if (!--count) { -+ lec_info(entry, buf); -+ return strlen(buf); -+ } -+ } -+ for(entry=lec_no_forward; -+ entry; entry=entry->next) { -+ if (!--count) { -+ lec_info(entry, buf); -+ return strlen(buf); -+ } -+ } -+ return 0; -+ } ++ ++ 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; @@ -14097,9 +14425,9 @@ /* * Called once on startup. */ ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/include/linux/atmlec.h Mon Sep 2 19:12:44 1996 -@@ -0,0 +1,58 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/atmlec.h Thu Sep 26 22:12:04 1996 +@@ -0,0 +1,64 @@ +/* + * + * ATM Lan Emulation Daemon vs. driver interface @@ -14119,13 +14447,18 @@ +#define ATMLEC_DATA _IO('a',ATMIOC_LANE+1) +#define ATMLEC_MCAST _IO('a',ATMIOC_LANE+2) + -+typedef enum { l_set_mac_addr, l_del_mac_addr, -+ l_flush_xmt, l_svc_setup, -+ l_add_permanent, l_addr_delete, -+ l_topology_change, l_flush_complete, -+ l_arp_update, l_reset, l_config, -+ l_flush_tran_id, l_set_lecid, -+ l_arp_xmt } atmlec_msg_type; ++/* Maximum number of LEC interfaces (tweakable) */ ++#define MAX_LEC_ITF 4 ++ ++typedef enum { ++ l_set_mac_addr, l_del_mac_addr, ++ l_flush_xmt, 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 { @@ -14154,13 +14487,14 @@ +}; + +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 Sep 9 20:17:39 1996 -+++ work/net/atm/lec.c Wed Aug 21 11:42:09 1996 -@@ -0,0 +1,612 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/lec.c Thu Sep 26 22:12:05 1996 +@@ -0,0 +1,642 @@ +/* + * lec.c: Lan Emulation driver + * Marko Kiiskila carnil@cs.tut.fi @@ -14191,9 +14525,6 @@ +/* +#define DPRINTK printk +*/ -+ -+struct atm_vcc *lecd = NULL; -+ +#define DUMP_PACKETS 0 /* 0 = None, + * 1 = 30 first bytes + * 2 = Whole packet @@ -14205,27 +14536,12 @@ +static struct enet_statistics *lec_get_stats(struct device *dev); +static int lec_init(struct device *dev); + -+static char myname[] = "lec0"; -+ -+extern struct lec_arp_table *lec_arp_empty_ones; ++/* will be lec0, lec1, lec2 etc. */ ++static char myname[] = "lecx"; + -+/* Have we register_netdev() yet? */ -+unsigned char registered = 0; -+ -+static struct device dev_lec = { -+ myname, -+ 0, 0, /* rmem_end, rmem_start */ -+ 0, 0, /* mem_end, mem_start */ -+ 0, 0, /* base_addr, irq */ -+ 0, 0, /* start, interrupt */ -+ 0, NULL, /* tbusy, *next */ -+ lec_init /* Initialization func */ -+}; -+ -+struct lec_priv { -+ struct enet_statistics stats; -+ unsigned short lecid; /* Lecid of this client */ -+}; ++/* Device structures */ ++struct device *dev_lec[MAX_LEC_ITF] = ++{NULL, NULL, NULL, NULL}; + +/* + * Open/initialize the netdevice. This is called (in the current kernel) @@ -14244,8 +14560,7 @@ + dev->tbusy = 0; + dev->start = 1; + dev->interrupt = 1; -+ if (priv) -+ memset(&priv->stats,0,sizeof(struct enet_statistics)); ++ memset(&priv->stats,0,sizeof(struct enet_statistics)); + + return 0; +} @@ -14263,10 +14578,9 @@ +#endif /* DUMP_PACKETS >0 */ + + DPRINTK("Lec_send_packet called\n"); -+ if (!lecd) { -+ printk("LEC:No lecd attached\n"); -+ if (priv) -+ priv->stats.tx_errors++; ++ if (!priv->lecd) { ++ printk("%s:No lecd attached\n",dev->name); ++ priv->stats.tx_errors++; + return -EUNATCH; + } + if (dev->tbusy) { @@ -14304,7 +14618,7 @@ + lec_h->le_header = htons(priv->lecid); + +#if DUMP_PACKETS > 0 -+ printk("LEC: send datalen:%ld lecid:%4.4x\n", ++ 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++) { @@ -14321,29 +14635,25 @@ + printk("%s...\n",buf); +#endif /* DUMP_PACKETS > 0 */ + /* Send to right vcc */ -+ send_vcc = lec_arp_resolve(lec_h->h_dest); -+ DPRINTK("send_vcc:%p vcc_flags:%x\n", ++ 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)) { -+ if (priv) -+ priv->stats.tx_errors++; -+ /* -+ DPRINTK("LEC:lec_send_packet: dropping ..\n"); -+ dev_kfree_skb(skb, FREE_WRITE); -+ return 0; -+ */ -+ DPRINTK("LEC:lec_send_packet: handing back...\n"); ++ 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("LEC:sending to vpi:%d vci:%d\n", ++ 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("LEC:data packet %ld / %d\n", ++ printk("%s:data packet %ld / %d\n", ++ dev->name, + skb->len,skb->truesize); + nb=(unsigned char*)kmalloc(64, + GFP_ATOMIC); @@ -14361,8 +14671,7 @@ + atomic_add(skb->truesize, &send_vcc->tx_inuse); + skb->atm.iovcnt = 0; + send_vcc->dev->ops->send(send_vcc, skb); -+ if (priv) -+ priv->stats.tx_packets++; ++ priv->stats.tx_packets++; + } + } + /* Should we wait for card's device driver to notify us? */ @@ -14497,60 +14806,66 @@ +static int +lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) +{ -+ struct lec_priv *priv = (struct lec_priv *)dev_lec.priv; ++ 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("LEC: msg from zeppelin:%d\n", mesg->type); ++ 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_lec.dev_addr[i] = mesg->content.normal.mac_addr[i]; ++ dev->dev_addr[i] = mesg->content.normal.mac_addr[i]; + } + break; + case l_del_mac_addr: + for(i=0;i<6;i++) { -+ dev_lec.dev_addr[i] = 0; ++ dev->dev_addr[i] = 0; + } + break; -+ case l_add_permanent: -+ lec_add_permanent(mesg->content.normal.mac_addr, -+ mesg->content.normal.atm_addr); -+ break; + case l_addr_delete: -+ lec_addr_delete(mesg->content.normal.atm_addr, ++ lec_addr_delete(priv, mesg->content.normal.atm_addr, + mesg->content.normal.flag); + break; + case l_topology_change: -+ lec_topology_flag_change_set(mesg->content.normal.flag); ++ priv->topology_change = mesg->content.normal.flag; + break; + case l_flush_complete: -+ lec_flush_complete(mesg->content.normal.atm_addr, ++ lec_flush_complete(priv, mesg->content.normal.atm_addr, + mesg->content.normal.flag); + break; + case l_arp_update: -+ lec_arp_update(mesg->content.normal.mac_addr, ++ lec_arp_update(priv, mesg->content.normal.mac_addr, + mesg->content.normal.atm_addr, + mesg->content.normal.flag); + break; -+ case l_reset: -+ lec_reset(); -+ break; + case l_config: -+ lec_config(&mesg->content.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(mesg->content.normal.mac_addr, ++ lec_set_flush_tran_id(priv, mesg->content.normal.mac_addr, + mesg->content.normal.flag); + break; + case l_set_lecid: -+ if (priv) -+ priv->lecid = (unsigned short)(0xffff&mesg->content.normal.flag); ++ priv->lecid=(unsigned short)(0xffff&mesg->content.normal.flag); + break; + default: -+ printk("LEC: Unknown message type %d\n",mesg->type); ++ printk("%s: Unknown message type %d\n", dev->name, mesg->type); + dev_kfree_skb(skb, FREE_WRITE); + return -EINVAL; + } @@ -14562,21 +14877,24 @@ +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; + -+ lecd = NULL; ++ priv->lecd = NULL; + /* Do something needful? */ + -+ dev_lec.tbusy = 1; -+ dev_lec.start = 0; ++ dev->tbusy = 1; ++ dev->start = 0; + -+ lec_arp_destroy(); ++ lec_arp_destroy(priv); + + if (skb_peek(&vcc->recvq)) -+ printk("LEC lec_atm_close: closing with messages pending\n"); ++ 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("LEC: Shut down!\n"); ++ printk("%s: Shut down!\n", dev->name); +} + +static struct atmdev_ops lecdev_ops = { @@ -14606,13 +14924,13 @@ +}; + +int -+send_to_lecd(atmlec_msg_type type, unsigned char *mac_addr, -+ unsigned char *atm_addr) ++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; -+ -+ if (!lecd) { ++ ++ if (!priv || !priv->lecd) { + return -1; + } + skb = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC); @@ -14627,9 +14945,9 @@ + if (atm_addr) + memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN); + -+ atomic_add(skb->truesize+ATM_PDU_OVHD, &lecd->rx_inuse); -+ skb_queue_tail(&lecd->recvq, skb); -+ wake_up(&lecd->sleep); ++ 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; +} + @@ -14637,7 +14955,7 @@ +lec_init(struct device *dev) +{ + dev->priv = kmalloc(sizeof(struct lec_priv), GFP_KERNEL); -+ if (dev->priv == NULL) ++ if (!dev->priv) + return -ENOMEM; + + memset(dev->priv,0,sizeof(struct lec_priv)); @@ -14656,7 +14974,7 @@ + dev->get_stats = lec_get_stats; + dev->set_multicast_list = NULL; + dev->do_ioctl = NULL; -+ printk("LEC: Initialized!\n"); ++ printk("%s: Initialized!\n",dev->name); + return 0; +} + @@ -14669,21 +14987,24 @@ +void +lec_push(struct atm_vcc *vcc, struct sk_buff *skb) +{ -+ struct lec_priv *priv = (struct lec_priv *)dev_lec.priv; ++ struct device *dev = (struct device *)vcc->proto_data; ++ struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lecdatahdr_8023 *hdr; +#if DUMP_PACKETS >0 + int i=0; + char buf[300]; + -+ printk("LEC: lec_push vcc vpi:%d vci:%d\n",vcc->vpi, vcc->vci); ++ printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name, ++ vcc->vpi, vcc->vci); +#endif + if (!skb) { -+ DPRINTK("LEC: null skb\n"); -+ lec_vcc_close(vcc); ++ DPRINTK("%s: null skb\n",dev->name); ++ lec_vcc_close(priv, vcc); + return; + } +#if DUMP_PACKETS > 0 -+ printk("LEC: rcv datalen:%ld lecid:%4.4x\n", skb->len, priv->lecid); ++ 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]); @@ -14699,32 +15020,33 @@ + printk("%s...\n",buf); +#endif /* DUMP_PACKETS > 0 */ + if (memcmp(skb->data, lec_ctrl_magic, 4) ==0) { /* Control frame, to daemon*/ -+ DPRINTK("LEC: To daemon\n"); ++ 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) || -+ !lecd) { /* Probably looping back, or if lecd is missing, -+ lecd has gone down */ ++ !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 (lec_arp_empty_ones) { /* FILTER DATA!!!! */ -+ lec_arp_check_empties(vcc, skb); ++ if (priv->lec_arp_empty_ones) { /* FILTER DATA!!!! */ ++ lec_arp_check_empties(priv, vcc, skb); + } -+ skb->dev = &dev_lec; ++ skb->dev = dev; + skb->mac.raw = (unsigned char *)skb->data; + skb->mac.ethernet = (struct ethhdr *)skb_pull(skb, 2); + if (*hdr->h_dest&1) { -+ if (memcmp(hdr->h_dest,dev_lec.broadcast, ETH_ALEN)==0) ++ if (memcmp(hdr->h_dest,dev->broadcast, ETH_ALEN)==0) + skb->pkt_type=PACKET_BROADCAST; + else + skb->pkt_type=PACKET_MULTICAST; -+ } else if (dev_lec.flags&(IFF_PROMISC|IFF_ALLMULTI)) { -+ if (memcmp(hdr->h_dest,dev_lec.dev_addr, ETH_ALEN)) ++ } 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) @@ -14733,8 +15055,7 @@ + skb->protocol = htons(ETH_P_802_2); + skb->h.raw = skb_pull(skb, ETH_HLEN); + netif_rx(skb); -+ if (priv) -+ priv->stats.rx_packets++; ++ priv->stats.rx_packets++; + } +} + @@ -14745,37 +15066,80 @@ + + /* Lecd must be up in this case */ + memcpy_fromfs(&ioc_data, arg, sizeof(struct atmlec_ioc)); -+ lec_vcc_added(&ioc_data, vcc, vcc->push); ++ 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) ++lecd_attach(struct atm_vcc *vcc, int arg) +{ -+ int result; ++ int i, result; ++ struct lec_priv *priv; + -+ if (lecd) { -+ printk("LEC: Lecd already contacted\n"); -+ return -EADDRINUSE; ++ 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; ++ lec_arp_init(priv); ++ } else { ++ priv = (struct lec_priv *)dev_lec[i]->priv; ++ if (priv->lecd) ++ return -EADDRINUSE; + } -+ -+ lec_arp_init(); -+ if (!registered) { -+ registered = 1; -+ if ((result =register_netdev(&dev_lec)) != 0) -+ return result; -+ } -+ lecd = vcc; ++ priv->lecd = vcc; + vcc->dev = &lecatm_dev; -+ vcc->flags |= ATM_VF_READY; ++ ++ vcc->proto_data = dev_lec[i]; ++ vcc->flags |= ATM_VF_READY | ATM_VF_META; + -+ return 0; -+} ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/lec.h Mon Sep 9 18:58:20 1996 -@@ -0,0 +1,53 @@ ++ /* 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; ++} +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/lec.h Fri Sep 27 15:23:43 1996 +@@ -0,0 +1,107 @@ +/* + * + * Lan Emulation client header file @@ -14789,6 +15153,7 @@ + +#include +#include ++#include + +#define LEC_HEADER_LEN 16 + @@ -14821,17 +15186,70 @@ + * + */ + -+int lecd_attach(struct atm_vcc *vcc); ++/* Hash table size */ ++#define LEC_ARP_TABLE_SIZE 16 ++ ++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(atmlec_msg_type type, unsigned char *mac_addr, -+ unsigned char *atm_addr); ++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_ + ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/lec_arpc.c Wed Aug 21 11:06:48 1996 -@@ -0,0 +1,1116 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/lec_arpc.c Thu Sep 26 22:24:46 1996 +@@ -0,0 +1,1048 @@ +#include +#include +#include @@ -14851,64 +15269,11 @@ +*/ +#define DEBUG_ARP_TABLE 0 + -+struct lec_arp_table *lec_arp_tables[LEC_ARP_TABLE_SIZE] = -+{ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* At least this gets */ -+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; /* initialized */ -+ -+/* Used for storing VCC's that don't have a MAC address attached yet */ -+struct lec_arp_table *lec_arp_empty_ones = NULL; -+ -+/* 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. */ -+struct lec_arp_table *lec_no_forward = NULL; -+ -+static atomic_t lec_arp_lock_var = 0; -+ -+struct atm_vcc *mcast_vcc = NULL; -+ +#define LEC_ARP_REFRESH_INTERVAL (3*HZ) + -+static void lec_arp_check_expire(unsigned long dumle); -+static __inline__ void lec_arp_expire_arp(unsigned long dumb); -+static void lec_clear_all(void); -+void dump_arp_table(void); -+ -+static struct timer_list lec_arp_timer = -+{ NULL,NULL, LEC_ARP_REFRESH_INTERVAL, 0L, &lec_arp_check_expire }; -+static unsigned char lec_freeze; -+ -+/* C10 */ -+static unsigned int lec_maximum_unknown_frame_count = 1; -+/* 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) */ -+static unsigned long lec_max_unknown_frame_time = (1*HZ); -+/* If no traffic has been sent in this vcc for this period of time, -+ vcc will be torn down (C12)*/ -+static unsigned long lec_vcc_timeout_period = (1200*HZ); -+/* 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)*/ -+static unsigned short lec_max_retry_count = 1; -+/* Max time the client will maintain an entry in its arp cache in -+ absence of a verification of that relationship (C17)*/ -+static unsigned long lec_aging_time = (300*HZ); -+/* Max time the client will maintain an entry in cache when -+ topology change flag is true (C18) */ -+static unsigned long lec_forward_delay_time = (15*HZ); -+/* Topology change flag (C19)*/ -+static int lec_topology_change = 0; -+/* Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE -+ cycle to take (C20)*/ -+static unsigned long lec_arp_response_time = (1*HZ); -+/* Time limit ot wait to receive an LE_FLUSH_RESPONSE after the -+ LE_FLUSH_REQUEST has been sent before taking recover action. (C21)*/ -+static unsigned long lec_flush_timeout = (4*HZ); -+/* 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) */ -+static unsigned long lec_path_switching_delay = (6*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 @@ -14917,39 +15282,33 @@ +#define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE -1)) + +static __inline__ void -+lec_arp_lock(void) ++lec_arp_lock(struct lec_priv *priv) +{ -+ atomic_inc(&lec_arp_lock_var); ++ atomic_inc(&priv->lec_arp_lock_var); +} + +static __inline__ void -+lec_arp_unlock(void) ++lec_arp_unlock(struct lec_priv *priv) +{ -+ atomic_dec(&lec_arp_lock_var); ++ atomic_dec(&priv->lec_arp_lock_var); +} + +/* + * Initialization of arp-cache + */ +void -+lec_arp_init(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 @@ -14973,7 +15332,8 @@ + * Insert entry to lec_arp_table + */ +static __inline__ void -+lec_arp_put(struct lec_arp_table *to_put) ++lec_arp_put(struct lec_arp_table **lec_arp_tables, ++ struct lec_arp_table *to_put) +{ + unsigned short place; + unsigned long flags; @@ -14990,14 +15350,14 @@ + 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]); -+ dump_arp_table(); +} + +/* + * Remove entry from lec_arp_table + */ +static __inline__ int -+lec_arp_remove(struct lec_arp_table *to_remove) ++lec_arp_remove(struct lec_arp_table **lec_arp_tables, ++ struct lec_arp_table *to_remove) +{ + unsigned short place; + struct lec_arp_table *tmp; @@ -15052,8 +15412,7 @@ + 0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3], + 0xff&to_remove->mac_addr[4], 0xff&to_remove->mac_addr[5]); + -+ dump_arp_table(); -+ return 0; ++ return 0; +} + +#if DEBUG_ARP_TABLE @@ -15078,14 +15437,20 @@ +#endif + +void -+dump_arp_table(void) ++dump_arp_table(struct lec_priv *priv) +{ +#if DEBUG_ARP_TABLE + int i,j, offset; + struct lec_arp_table *rulla; + char buf[512]; ++ 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:\n"); ++ 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,"->%lx\n",(long)rulla->next); ++ rulla = rulla->next; ++ printk("%s",buf); ++ } + rulla = lec_arp_empty_ones; + if (rulla) + printk("Empty ones\n"); @@ -15151,15 +15547,66 @@ + rulla = rulla->next; + printk("%s",buf); + } ++ +#endif +} + ++/* ++ * Destruction of arp-cache ++ */ ++void ++lec_arp_destroy(struct lec_priv *priv) ++{ ++ 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); ++} ++ + +/* + * Find entry by mac_address + */ +static __inline__ struct lec_arp_table* -+lec_arp_find(unsigned char *mac_addr) ++lec_arp_find(struct lec_priv *priv, ++ unsigned char *mac_addr) +{ + unsigned short place; + struct lec_arp_table *to_return; @@ -15167,24 +15614,23 @@ + 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(); ++ lec_arp_lock(priv); + place = HASH(mac_addr[ETH_ALEN-1]); + -+ to_return = lec_arp_tables[place]; ++ to_return = priv->lec_arp_tables[place]; + while(to_return) { + if (memcmp(mac_addr, to_return->mac_addr, ETH_ALEN) == 0) { -+ to_return->last_used = jiffies; -+ lec_arp_unlock(); ++ lec_arp_unlock(priv); + return to_return; + } + to_return = to_return->next; + } -+ lec_arp_unlock(); ++ lec_arp_unlock(priv); + return NULL; +} + +static struct lec_arp_table* -+make_entry(unsigned char *mac_addr) ++make_entry(struct lec_priv *priv, unsigned char *mac_addr) +{ + struct lec_arp_table *to_return; + @@ -15196,8 +15642,11 @@ + } + 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; +} + @@ -15212,17 +15661,17 @@ + struct lec_arp_table *entry; + + entry = (struct lec_arp_table *)data; ++ + del_timer(&entry->timer); + + if (entry->status == ESI_ARP_PENDING) { -+ send_to_lecd(l_arp_xmt, entry->mac_addr, NULL); -+ entry->no_tries++; -+ if(entry->no_tries <= lec_max_retry_count) { -+ entry->timer.expires = jiffies + (1*HZ); -+ add_timer(&entry->timer); -+ } else -+ /* For safety */ -+ entry->timer.next = entry->timer.prev = NULL; ++ 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); + } +} + @@ -15235,27 +15684,30 @@ +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: lec_arp_expire_vcc vpi:%d vci:%d\n", ++ DPRINTK("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n", ++ to_remove, priv, + to_remove->vcc?to_remove->vcc->vpi:0, + to_remove->vcc?to_remove->vcc->vci:0); -+ if (to_remove == lec_arp_empty_ones) -+ lec_arp_empty_ones = to_remove->next; ++ 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 = lec_arp_empty_ones; ++ 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 == lec_no_forward) { -+ lec_no_forward = to_remove->next; ++ if (to_remove == priv->lec_no_forward) { ++ priv->lec_no_forward = to_remove->next; + } else { -+ entry = lec_no_forward; ++ entry = priv->lec_no_forward; + while (entry && entry->next != to_remove) + entry = entry->next; + if (entry) @@ -15282,26 +15734,31 @@ + * regardless of the progress of the flush protocol. + */ +static void -+lec_arp_check_expire(unsigned long dumle) ++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(&lec_arp_timer); ++ del_timer(&priv->lec_arp_timer); + -+ DPRINTK("lec_arp_check_expire %d\n",lec_arp_lock_var); -+ if (!lec_arp_lock_var) { -+ lec_arp_lock(); ++ 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 && -+ lec_topology_change) -+ time_to_check = lec_forward_delay_time; ++ priv->topology_change) ++ time_to_check=priv->forward_delay_time; + else -+ time_to_check = lec_aging_time; ++ time_to_check = priv->aging_time; + + DPRINTK("About to expire: %lx - %lx > %lx\n", + now,entry->last_used, time_to_check); @@ -15309,9 +15766,8 @@ + !(entry->flags & LEC_PERMANENT_FLAG)) { + /* Remove entry */ + printk("LEC:Remove entry1\n"); -+ del_timer(&entry->timer); + next = entry->next; -+ lec_arp_remove(entry); ++ lec_arp_remove(lec_arp_tables, entry); + kfree(entry); + entry = next; + } else { @@ -15320,14 +15776,14 @@ + entry->status == ESI_ARP_PENDING) + && + now-entry->timestamp >= -+ lec_max_unknown_frame_time) { ++ priv->max_unknown_frame_time) { + entry->timestamp = jiffies; + entry->packets_flooded = 0; + } + if (entry->status == ESI_FLUSH_PENDING + && + now-entry->timestamp >= -+ lec_path_switching_delay) { ++ priv->path_switching_delay) { + entry->last_used = jiffies; + entry->status = + ESI_FORWARD_DIRECT; @@ -15336,79 +15792,10 @@ + } + } + } -+ lec_arp_unlock(); ++ lec_arp_unlock(priv); + } -+ lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL; -+ if (!lec_freeze) -+ add_timer(&lec_arp_timer); -+} -+ -+/* -+ * Remove all entries -+ */ -+static void -+lec_clear_all(void) -+{ -+ struct lec_arp_table *entry, *next; -+ unsigned long flags; -+ int i; -+ -+ save_flags(flags); -+ cli(); -+ -+ for (i=0;inext; -+ lec_arp_remove(entry); -+ kfree(entry); -+ } -+ } -+ entry = lec_arp_empty_ones; -+ while(entry) { -+ next = entry->next; -+ del_timer(&entry->timer); -+ lec_arp_clear_vccs(entry); -+ kfree(entry); -+ entry = next; -+ } -+ lec_arp_empty_ones = NULL; -+ entry = lec_no_forward; -+ while(entry) { -+ next = entry->next; -+ del_timer(&entry->timer); -+ lec_arp_clear_vccs(entry); -+ kfree(entry); -+ entry = next; -+ } -+ lec_no_forward = NULL; -+ mcast_vcc = NULL; /* To make sure... */ -+ memset(lec_arp_tables, 0, -+ sizeof(struct lec_arp_table*)*LEC_ARP_TABLE_SIZE); -+ restore_flags(flags); -+} -+ -+/* -+ * Remove all entries not marked permanent -+ */ -+void -+lec_reset(void) -+{ -+ int i; -+ struct lec_arp_table *entry, *next; -+ -+ lec_arp_lock(); -+ -+ printk("lec_reset\n"); -+ for(i=0;inext; -+ if (!(entry->flags & LEC_PERMANENT_FLAG)) { -+ lec_arp_remove(entry); -+ kfree(entry); -+ } -+ } -+ } -+ lec_arp_unlock(); ++ priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL; ++ add_timer(&priv->lec_arp_timer); +} + +/* @@ -15416,109 +15803,82 @@ + * + */ +struct atm_vcc* -+lec_arp_resolve(unsigned char *mac_to_find) ++lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find) +{ + struct lec_arp_table *entry; + + if (mac_to_find[0]&0x01) { -+ return mcast_vcc; ++ return priv->mcast_vcc; + } -+ entry = lec_arp_find(mac_to_find); ++ 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) { -+ /* We want arp-request to be sent */ -+ entry->status = ESI_ARP_PENDING; -+ entry->timestamp = jiffies; -+ entry->no_tries = 1; -+ entry->packets_flooded=1; -+ send_to_lecd(l_arp_xmt, mac_to_find, NULL); + del_timer(&entry->timer); -+ entry->timer.expires = jiffies + (1*HZ); -+ entry->timer.function = lec_arp_expire_arp; -+ add_timer(&entry->timer); -+ return mcast_vcc; ++ 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_flooded < lec_maximum_unknown_frame_count) { ++ entry->packets_floodedmaximum_unknown_frame_count) { + entry->packets_flooded++; + DPRINTK("LEC_ARP: Flooding..\n"); -+ return mcast_vcc; ++ return priv->mcast_vcc; + } + return NULL; + } else { + /* No matching entry was found */ -+ entry = make_entry(mac_to_find); ++ entry = make_entry(priv, mac_to_find); + DPRINTK("LEC_ARP: Making entry\n"); + if (!entry) { -+ return mcast_vcc; ++ return priv->mcast_vcc; + } ++ lec_arp_put(priv->lec_arp_tables, entry); ++ init_timer(&entry->timer); ++ 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(l_arp_xmt, mac_to_find, NULL); -+ ++ 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); -+ lec_arp_put(entry); -+ return mcast_vcc; -+ } -+} -+ -+/* -+ * Add permanent entry to arp table. -+ */ -+struct lec_arp_table* -+lec_add_permanent(unsigned char *mac_addr, unsigned char *atmaddr) -+{ -+ struct lec_arp_table *to_add; -+ -+ to_add = make_entry(mac_addr); -+ if (!to_add) { -+ return NULL; ++ return priv->mcast_vcc; + } -+ memcpy(to_add->atm_addr, atmaddr, ATM_ESA_LEN); -+ to_add->flags |= LEC_PERMANENT_FLAG; -+ to_add->last_used = jiffies; -+ /* Connection forming must be started */ -+ send_to_lecd(l_svc_setup, NULL, atmaddr); -+ lec_arp_lock(); -+ lec_arp_put(to_add); -+ lec_arp_unlock(); -+ return to_add; +} + +int -+lec_addr_delete(unsigned char *atm_addr, unsigned long permanent) ++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(); ++ lec_arp_lock(priv); + printk("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(entry); ++ lec_arp_remove(priv->lec_arp_tables, entry); + kfree(entry); + } -+ lec_arp_unlock(); ++ lec_arp_unlock(priv); + return 0; + } + } -+ lec_arp_unlock(); ++ lec_arp_unlock(priv); + return -1; +} + @@ -15526,9 +15886,8 @@ + * Notifies: Response to arp_request (atm_addr != NULL) + */ +void -+lec_arp_update(unsigned char *mac_addr, -+ unsigned char *atm_addr, -+ unsigned long remoteflag) ++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; @@ -15536,12 +15895,12 @@ + 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]); -+ dump_arp_table(); -+ lec_arp_lock(); -+ if (lec_arp_empty_ones) { -+ entry = lec_arp_empty_ones; ++ dump_arp_table(priv); ++ 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)) { -+ lec_arp_empty_ones = entry->next; ++ priv->lec_arp_empty_ones = entry->next; + } else { + while(entry->next && memcmp(entry->next->atm_addr, + atm_addr, ATM_ESA_LEN)) @@ -15556,41 +15915,43 @@ + } + if (entry) { + del_timer(&entry->timer); -+ tmp = lec_arp_find(mac_addr); ++ 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); -+ lec_arp_put(tmp); ++ 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(); ++ lec_arp_unlock(priv); + DPRINTK("After update\n"); -+ dump_arp_table(); ++ dump_arp_table(priv); + return; + } + } -+ entry = lec_arp_find(mac_addr); ++ entry = lec_arp_find(priv, mac_addr); + if (!entry) { -+ entry = make_entry(mac_addr); ++ entry = make_entry(priv, mac_addr); + entry->status = ESI_UNKNOWN; -+ lec_arp_put(entry); ++ 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;inext) { ++ for(tmp=priv->lec_arp_tables[i];tmp;tmp=tmp->next) { + if (entry != tmp && + !memcmp(tmp->atm_addr, atm_addr, + ATM_ESA_LEN)) { @@ -15615,39 +15976,39 @@ + if (entry->status == ESI_ARP_PENDING || + entry->status == ESI_UNKNOWN) { + entry->status = ESI_VC_PENDING; -+ send_to_lecd(l_svc_setup, NULL, atm_addr); ++ send_to_lecd(priv, l_svc_setup, NULL, atm_addr); + } + DPRINTK("After update2\n"); -+ dump_arp_table(); -+ lec_arp_unlock(); ++ dump_arp_table(priv); ++ lec_arp_unlock(priv); +} + +/* + * Notifies: Vcc setup ready + */ +void -+lec_vcc_added(struct atmlec_ioc *ioc_data, -+ struct atm_vcc *vcc, -+ void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb)) ++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(); ++ lec_arp_lock(priv); + if (ioc_data->receive == 2) { + /* Vcc for BUS distribute */ + DPRINTK("LEC_ARP: Attaching mcast distribute\n"); -+ entry = lec_arp_find(bus_mac); ++ entry = lec_arp_find(priv, bus_mac); + if (!entry) { + printk("LEC_ARP: Multicast entry not found!\n"); -+ lec_arp_unlock(); ++ 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(); ++ lec_arp_unlock(priv); + return; + } else if (ioc_data->receive == 1) { + /* Vcc which we don't want to make default vcc, attach it @@ -15663,18 +16024,18 @@ + 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(bus_mac); ++ 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 + lec_vcc_timeout_period; ++ entry->timer.expires = jiffies + priv->vcc_timeout_period; + entry->timer.function = lec_arp_expire_vcc; -+ entry->next = lec_no_forward; -+ lec_no_forward = entry; -+ lec_arp_unlock(); -+ dump_arp_table(); ++ 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", @@ -15689,7 +16050,7 @@ + ioc_data->atm_addr[16],ioc_data->atm_addr[17], + ioc_data->atm_addr[18],ioc_data->atm_addr[19]); + for (i=0;inext) { ++ for (entry = priv->lec_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"); @@ -15704,14 +16065,15 @@ + entry->vcc = vcc; + entry->old_push = old_push; + if (entry->status == ESI_VC_PENDING) { -+ if (lec_maximum_unknown_frame_count==0) ++ if(priv->maximum_unknown_frame_count ++ ==0) + entry->status = + ESI_FORWARD_DIRECT; + else { + entry->timestamp = jiffies; + entry->status = + ESI_FLUSH_PENDING; -+ send_to_lecd(l_flush_xmt, ++ send_to_lecd(priv,l_flush_xmt, + entry->mac_addr, + entry->atm_addr); + } @@ -15731,44 +16093,45 @@ + } + } + if (found_entry) { -+ lec_arp_unlock(); ++ lec_arp_unlock(priv); + DPRINTK("After vcc was added\n"); -+ dump_arp_table(); ++ dump_arp_table(priv); + return; + } + /* Not found, snatch address from first data packet that arrives from + this vcc */ -+ entry = make_entry(bus_mac); ++ 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 = lec_arp_empty_ones; -+ lec_arp_empty_ones = entry; -+ entry->timer.expires = jiffies + lec_vcc_timeout_period; ++ 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(); ++ lec_arp_unlock(priv); + DPRINTK("After vcc was added\n"); -+ dump_arp_table(); ++ dump_arp_table(priv); +} + +void -+lec_flush_complete(unsigned char *atm_addr, unsigned long tran_id) ++lec_flush_complete(struct lec_priv *priv, ++ unsigned char *atm_addr, unsigned long tran_id) +{ + struct lec_arp_table *entry; + int i; + + DPRINTK("LEC:lec_flush_complete\n"); + for (i=0;inext) { ++ for (entry=priv->lec_arp_tables[i];entry;entry=entry->next) { + if (memcmp(atm_addr, entry->atm_addr,ATM_ESA_LEN)==0 && + entry->flush_tran_id == tran_id) { + DPRINTK("entry->status:%d\n",entry->status); + entry->status = ESI_FORWARD_DIRECT; + DPRINTK("LEC_ARP: Flushed\n"); -+ dump_arp_table(); ++ dump_arp_table(priv); + return; + } + } @@ -15783,18 +16146,13 @@ + 0xff&atm_addr[18],0xff&atm_addr[19]); +} + -+void -+lec_topology_flag_change_set(unsigned long topology_change_flag) -+{ -+ lec_topology_change = topology_change_flag; -+} -+ +void -+lec_set_flush_tran_id(unsigned char *mac_addr, unsigned long tran_id) ++lec_set_flush_tran_id(struct lec_priv *priv, ++ unsigned char *mac_addr, unsigned long tran_id) +{ + struct lec_arp_table *entry; + -+ entry = lec_arp_find(mac_addr); ++ entry = lec_arp_find(priv, mac_addr); + if (!entry) { + printk("LEC_ARP: Set_flush_tran_id: entry not found\n"); + return; @@ -15804,124 +16162,116 @@ +} + +int -+lec_mcast_attach(struct atm_vcc *vcc) ++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(); -+ to_add = make_entry(mac_addr); ++ 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->vcc = vcc; + to_add->old_push = vcc->push; + vcc->push = lec_push; -+ mcast_vcc = vcc; -+ lec_arp_put(to_add); -+ lec_arp_unlock(); ++ priv->mcast_vcc = vcc; ++ lec_arp_put(priv->lec_arp_tables, to_add); ++ lec_arp_unlock(priv); + return 0; +} + +void -+lec_config(struct atmlec_config_msg *conf) -+{ -+ lec_maximum_unknown_frame_count = conf->maximum_unknown_frame_count; -+ lec_max_unknown_frame_time = (conf->max_unknown_frame_time*HZ); -+ lec_max_retry_count = conf->max_retry_count; -+ lec_aging_time = (conf->aging_time*HZ); -+ lec_forward_delay_time = (conf->forward_delay_time*HZ); -+ lec_arp_response_time = (conf->arp_response_time*HZ); -+ lec_flush_timeout = (conf->flush_timeout*HZ); -+ lec_path_switching_delay = (conf->path_switching_delay*HZ); -+} -+ -+void -+lec_vcc_close(struct atm_vcc *vcc) ++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(); -+ lec_arp_lock(); ++ 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(entry); ++ lec_arp_remove(priv->lec_arp_tables,entry); + kfree(entry); -+ if (mcast_vcc == vcc) { -+ mcast_vcc = NULL; ++ if (priv->mcast_vcc == vcc) { ++ priv->mcast_vcc = NULL; + } + } else if (vcc == entry->recv_vcc) { + /* Bus distribution closed */ -+ mcast_vcc = NULL; -+ lec_arp_remove(entry); ++ priv->mcast_vcc = NULL; ++ lec_arp_remove(priv->lec_arp_tables,entry); + kfree(entry); -+ lec_arp_unlock(); ++ lec_arp_unlock(priv); + vcc->push(vcc, NULL); + return; + } + } + } -+ entry=lec_arp_empty_ones; ++ entry=priv->lec_arp_empty_ones; + while(entry && entry->vcc==vcc) { + lec_arp_clear_vccs(entry); -+ lec_arp_empty_ones=entry->next; ++ priv->lec_arp_empty_ones=entry->next; ++ del_timer(&entry->timer); + kfree(entry); -+ entry=lec_arp_empty_ones; ++ 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=lec_no_forward; ++ entry=priv->lec_no_forward; + while(entry && entry->recv_vcc==vcc) { + lec_arp_clear_vccs(entry); -+ lec_no_forward=entry->next; ++ priv->lec_no_forward=entry->next; ++ del_timer(&entry->timer); + kfree(entry); -+ entry=lec_no_forward; ++ 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(); -+ dump_arp_table(); ++ lec_arp_unlock(priv); ++ dump_arp_table(priv); +} + +void -+lec_arp_check_empties(struct atm_vcc *vcc, struct sk_buff *skb) ++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; + -+ lec_arp_lock(); -+ entry = lec_arp_empty_ones; ++ lec_arp_lock(priv); ++ entry = priv->lec_arp_empty_ones; + if (vcc == entry->vcc) { + del_timer(&entry->timer); + memcpy(entry->mac_addr, hdr->h_source, ETH_ALEN); + entry->status = ESI_FORWARD_DIRECT; + entry->last_used = jiffies; -+ lec_arp_empty_ones = entry->next; ++ priv->lec_arp_empty_ones = entry->next; + /* We might have got an entry */ -+ if ((prev=lec_arp_find(hdr->h_source))) { -+ lec_arp_remove(prev); ++ if ((prev=lec_arp_find(priv,hdr->h_source))) { ++ lec_arp_remove(priv->lec_arp_tables, prev); + kfree(prev); + } -+ lec_arp_put(entry); -+ lec_arp_unlock(); ++ lec_arp_put(priv->lec_arp_tables, entry); ++ lec_arp_unlock(priv); + return; + } + prev = entry; @@ -15932,7 +16282,7 @@ + } + if (!entry) { + DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n"); -+ lec_arp_unlock(); ++ lec_arp_unlock(priv); + return; + } + del_timer(&entry->timer); @@ -15940,17 +16290,17 @@ + entry->status = ESI_FORWARD_DIRECT; + entry->last_used = jiffies; + prev->next = entry->next; -+ if ((prev = lec_arp_find(hdr->h_source))) { -+ lec_arp_remove(prev); ++ if ((prev = lec_arp_find(priv, hdr->h_source))) { ++ lec_arp_remove(priv->lec_arp_tables,prev); + kfree(prev); + } -+ lec_arp_put(entry); -+ lec_arp_unlock(); ++ lec_arp_put(priv->lec_arp_tables,entry); ++ lec_arp_unlock(priv); +} + ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/net/atm/lec_arpc.h Mon Sep 9 18:58:20 1996 -@@ -0,0 +1,104 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/net/atm/lec_arpc.h Fri Sep 27 15:23:43 1996 +@@ -0,0 +1,102 @@ +/* + * Lec arp cache + * Marko Kiiskila carnil@cs.tut.fi @@ -15993,6 +16343,7 @@ + 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 */ +}; + +/* Status fields */ @@ -16028,35 +16379,32 @@ +#define LEC_REMOTE_FLAG 0x0001 +#define LEC_PERMANENT_FLAG 0x0002 + -+/* Hash table size */ -+#define LEC_ARP_TABLE_SIZE 16 -+ +/* Protos */ -+void lec_reset(void); -+void lec_arp_init(void); -+int lec_mcast_attach(struct atm_vcc *vcc); -+void lec_arp_destroy(void); -+void lec_vcc_close(struct atm_vcc *vcc); -+ -+struct atm_vcc *lec_arp_resolve(unsigned char *mac_to_addr); -+void lec_vcc_added(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 atm_vcc *vcc, struct sk_buff *skb); -+struct lec_arp_table *lec_add_permanent(unsigned char *mac_addr, -+ unsigned char *atmaddr); -+int lec_addr_delete(unsigned char *mac_addr, unsigned long permanent); -+void lec_topology_flag_change_set(unsigned long topology_change_flag); -+void lec_flush_complete(unsigned char *atm_addr, unsigned long tran_id); -+void lec_arp_update(unsigned char *mac_addr, unsigned char *atm_addr, -+ unsigned long remoteflag); -+void lec_set_flush_tran_id(unsigned char *mac_addr, unsigned long tran_id); -+void lec_config(struct atmlec_config_msg *conf); -+void lec_arp_check(unsigned char *to_check); -+void lec_proc_info(char *buf); ++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 char *atm_addr, 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 Tue Aug 20 17:14:55 1996 -+++ work/include/net/route.h Mon Sep 9 18:57:34 1996 ++++ work/include/net/route.h Fri Sep 27 15:22:44 1996 @@ -26,6 +26,7 @@ #define _ROUTE_H @@ -16120,7 +16468,7 @@ #endif /* _ROUTE_H */ --- ref/include/net/sock.h Tue Aug 20 17:11:40 1996 -+++ work/include/net/sock.h Mon Sep 9 18:45:07 1996 ++++ work/include/net/sock.h Fri Sep 27 15:20:29 1996 @@ -301,7 +301,13 @@ int ip_mc_loop; /* Loopback */ char ip_mc_name[MAX_ADDR_LEN];/* Multicast device name */ @@ -16136,9 +16484,9 @@ /* * This part is used for the timeout functions (timer.c). ---- /dev/null Mon Sep 9 20:17:39 1996 -+++ work/include/linux/arequipa.h Mon Sep 9 18:58:20 1996 -@@ -0,0 +1,45 @@ +--- /dev/null Mon Jul 18 01:46:18 1994 ++++ work/include/linux/arequipa.h Fri Sep 27 22:23:31 1996 +@@ -0,0 +1,55 @@ +/* arequipa.h - Arequipa interface definitions */ + +/* Written 1996 by Jean-Michel Pittet and Werner Almesberger, EPFL LRC */ @@ -16149,6 +16497,15 @@ + +#include + ++/* ++ * Arequipa is identified by a so-called "Vendor-Specific Application ++ * identifier" in the Q.2931 B-HLI IE. That identifier consists of three ++ * bytes with the OUI, followed by four bytes assigned by the organization ++ * owning the OUI. ++ */ ++ ++#define EPFL_OUI "\x00\x60\xD7" ++#define AREQUIPA_HLT_VS_ID EPFL_OUI "\x01\x00\x00\x01" + +#define AREQUIPA_PRESET _IO('a',ATMIOC_AREQUIPA) +#define AREQUIPA_INCOMING _IO('a',ATMIOC_AREQUIPA+1) @@ -16171,7 +16528,8 @@ +extern struct device *arequipa_dev; + +int atm_init_arequipa(void); -+int arequipa_attach(struct socket *lower,struct sock *upper); ++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); @@ -16185,7 +16543,7 @@ + +#endif --- ref/net/ipv4/tcp_input.c Thu Aug 1 14:25:59 1996 -+++ work/net/ipv4/tcp_input.c Wed Aug 21 10:56:28 1996 ++++ work/net/ipv4/tcp_input.c Fri Sep 27 14:53:00 1996 @@ -36,6 +36,11 @@ #include #include @@ -16209,7 +16567,7 @@ + if (newsk->aq_route) { + if (dev == arequipa_dev) + (void) arequipa_attach(skb->atm.vcc->sock, -+ newsk); ++ newsk,skb->atm.generation); + } + else { + if (sk->opt) kfree(sk->opt); @@ -16232,7 +16590,7 @@ if(rt!=NULL && (rt->rt_flags&RTF_WINDOW)) newsk->window_clamp = rt->rt_window; -@@ -1785,6 +1808,12 @@ +@@ -1785,6 +1808,13 @@ skb->free = 1; skb->saddr = daddr; skb->daddr = saddr; @@ -16240,7 +16598,8 @@ +#ifdef CONFIG_AREQUIPA + if (dev == arequipa_dev && !sk->arequipa && sk->aq_route && + sk->state == TCP_ESTABLISHED) -+ (void) arequipa_attach(skb->atm.vcc->sock,sk); ++ (void) arequipa_attach(skb->atm.vcc->sock,sk, ++ skb->atm.generation); +#endif /* diff -ur --new-file old/atm/debug/Makefile new/atm/debug/Makefile --- old/atm/debug/Makefile Mon Sep 2 19:41:13 1996 +++ new/atm/debug/Makefile Thu Sep 26 20:52:26 1996 @@ -1,4 +1,4 @@ -SYSPGMS=ed encopy endump zndump +SYSPGMS=ed encopy endump zndump znth MAN8= include ../Rules.make diff -ur --new-file old/atm/debug/znth.c new/atm/debug/znth.c --- old/atm/debug/znth.c Thu Jan 1 01:00:00 1970 +++ new/atm/debug/znth.c Thu Sep 26 21:19:48 1996 @@ -0,0 +1,55 @@ +/* znth.c - ZN122x timestamp adjustments history */ + +/* Written 1996 by Werner Almesberger, EPFL-LRC */ + + +#include +#include +#include +#include +#include +#include + +#include "/usr/src/linux/drivers/atm/zatm.h" + + +int main(int argc,char **argv) +{ + struct atmif_sioc sioc; + struct zatm_thist history[ZATM_TIMER_HISTORY_SIZE]; + char *end; + int s,i; + + if (argc != 2 || ((sioc.number = strtoul(argv[1],&end,0)), *end)) { + fprintf(stderr,"usage: %s itf\n",*argv); + return 1; + } + if ((s = socket(PF_ATMPVC,SOCK_DGRAM,0)) < 0) { + perror("socket"); + return 1; + } + sioc.arg = history; + sioc.length = sizeof(history); + if (ioctl(s,ZATM_GETTHIST,&sioc) < 0) { + perror("ioctl ZATM_GETTHIST"); + return 1; + } + for (i = 0; i < ZATM_TIMER_HISTORY_SIZE; i++) { + struct timeval diff; + + if (!history[i].real.tv_sec) continue; + printf("%2d:%02d:%02d.%06d: ",(history[i].real.tv_sec/3600) % 24, + (history[i].real.tv_sec/60) % 60,history[i].real.tv_sec % 60, + history[i].real.tv_usec); + history[i].expected.tv_sec += history[i].expected.tv_usec/1000000; + history[i].expected.tv_usec %= 1000000; + diff.tv_sec = history[i].expected.tv_sec-history[i].real.tv_sec; + diff.tv_usec = history[i].expected.tv_usec-history[i].real.tv_usec; + if (diff.tv_sec < -2000 || diff.tv_sec > 2000) + printf("%11d SECONDS\n",diff.tv_sec); + else { + diff.tv_usec += diff.tv_sec*1000000; + printf("%11d usec\n",diff.tv_usec); + } + } +} diff -ur --new-file old/atm/doc/usage.tex new/atm/doc/usage.tex --- old/atm/doc/usage.tex Mon Sep 9 20:17:56 1996 +++ new/atm/doc/usage.tex Fri Sep 27 22:47:28 1996 @@ -1,7 +1,7 @@ %%def%:= %:\begin{verbatim} -%:Usage instructions - ATM on Linux, release 0.18 (pre-alpha) +%:Usage instructions - ATM on Linux, release 0.19 (pre-alpha) %:------------------------------------------------------------- %: %:\end{verbatim} @@ -38,14 +38,14 @@ \title{ATM on Linux \\ User's guide \\ - Release 0.18 (pre-alpha)} + Release 0.19 (pre-alpha)} \author{Werner Almesberger \\ {\tt werner.almesberger@lrc.di.epfl.ch} \\ \\ Laboratoire de R\'eseaux de Communication (LRC) \\ EPFL, CH-1015 Lausanne, Switzerland} -\date{August 21, 1996} +\date{September 27, 1996} \begin{document} \maketitle @@ -135,7 +135,7 @@ \name{les} \item[\path{atm/aqd/}] Arequipa demon: \name{arequipad} \item[\path{atm/debug/}] Debugging tools: \name{ed}, \name{en}, - \name{encopy}, \name{endump}, and \name{zndump} + \name{encopy}, \name{endump}, \name{zndump}, and \name{znth} \item[\path{atm/lib/}] Libraries for applications and demons \item[\path{atm/doc/}] Documentation in \LaTeX\ and conversion tools \end{description} @@ -159,6 +159,7 @@ Enable extended debugging (CONFIG_ATM_ENI_DEBUG) ZeitNet ZN1221/ZN1225 (CONFIG_ATM_ZATM) Enable extended debugging (CONFIG_ATM_ZATM_DEBUG) + Enable usec resolution timestamps (CONFIG_ATM_ZATM_EXACT_TS) Rolfs TI TNETA1570 (CONFIG_ATM_TNETA1570) Enable extended debugging (CONFIG_ATM_TNETA1570_DEBUG) \end{verbatim} diff -ur --new-file old/atm/doc/usage.txt new/atm/doc/usage.txt --- old/atm/doc/usage.txt Mon Sep 9 20:19:42 1996 +++ new/atm/doc/usage.txt Fri Sep 27 23:02:47 1996 @@ -1,4 +1,4 @@ -Usage instructions - ATM on Linux, release 0.18 (pre-alpha) +Usage instructions - ATM on Linux, release 0.19 (pre-alpha) ------------------------------------------------------------- For updates of ATM on Linux, please check the Web page at @@ -60,7 +60,7 @@ atm/led/ LAN Emulation demon: led atm/lane/ LAN Emulation servers: bus, lecs, les atm/aqd/ Arequipa demon: arequipad - atm/debug/ Debugging tools: ed, en, encopy, endump, and zndump + atm/debug/ Debugging tools: ed, en, encopy, endump, zndump, and znth atm/lib/ Libraries for applications and demons atm/doc/ Documentation in LaTeX and conversion tools @@ -83,6 +83,7 @@ Enable extended debugging (CONFIG_ATM_ENI_DEBUG) ZeitNet ZN1221/ZN1225 (CONFIG_ATM_ZATM) Enable extended debugging (CONFIG_ATM_ZATM_DEBUG) + Enable usec resolution timestamps (CONFIG_ATM_ZATM_EXACT_TS) Rolfs TI TNETA1570 (CONFIG_ATM_TNETA1570) Enable extended debugging (CONFIG_ATM_TNETA1570_DEBUG) diff -ur --new-file old/atm/ip/atmarp.8 new/atm/ip/atmarp.8 --- old/atm/ip/atmarp.8 Mon Sep 2 19:38:24 1996 +++ new/atm/ip/atmarp.8 Thu Sep 26 15:37:29 1996 @@ -1,4 +1,4 @@ -.TH ATMARP 8 "Sep 2, 1996" "Linux" "Maintenance Commands" +.TH ATMARP 8 "Sep 26, 1996" "Linux" "Maintenance Commands" .SH NAME atmarp \- administer classical IP over ATM connections .SH SYNOPSIS @@ -16,6 +16,7 @@ .RB [\fIitf\fP.]\fIvpi\fP.\fIvci\fP .RB [ pcr\ \fIvalue\fP ] .RB [ temp ] +.RB [ pub ] .RB [ null ] .br .B atmarp @@ -24,6 +25,7 @@ .RB \fIatm_addr\fP .RB [ pcr\ \fIvalue\fP ] .RB [ temp ] +.RB [ pub ] .RB [ arpsrv ] .br .B atmarp @@ -56,6 +58,9 @@ .IP \fBtemp\fP does not mark the entry as permanent, i.e. it will time out and then be removed. +.IP \fBpub\fP +publishes the entry (only relevant for ATMARP server). ATMARP requests for +entries not marked for publishing yield an ATMARP_NAK response. .IP \fBnull\fP uses NULL encapsulation instead of LLC/SNAP encapsulation on the PVC. This option is not available for SVCs, because the LLC/SNAP header is required diff -ur --new-file old/atm/ip/atmarp.c new/atm/ip/atmarp.c --- old/atm/ip/atmarp.c Mon Sep 9 19:34:59 1996 +++ new/atm/ip/atmarp.c Thu Sep 26 16:38:06 1996 @@ -20,7 +20,7 @@ #include #include #include /* for MAX_ADDR_LEN for if_arp.h */ -#include /* for ATF_PERM */ +#include /* for ATF_PERM and ATF_PUBL */ #include "atm.h" @@ -56,10 +56,10 @@ { fprintf(stderr,"usage: %s -a\n",name); fprintf(stderr,"%6s %s -c [[atm]N]\n","",name); - fprintf(stderr,"%6s %s -s ip_addr [itf.]vpi.vci [pcr value] [temp] [null]" - "\n","",name); - fprintf(stderr,"%6s %s -s ip_addr atm_addr [pcr value] [temp] [arpsrv]\n", - "",name); + fprintf(stderr,"%6s %s -s ip_addr [itf.]vpi.vci [pcr value] [temp] [pub]" + " [null]\n","",name); + fprintf(stderr,"%6s %s -s ip_addr atm_addr [pcr value] [temp] [pub] " + "[arpsrv]\n","",name); fprintf(stderr,"%6s %s -d ip_addr [arpsrv]\n","",name); exit(1); } @@ -151,6 +151,7 @@ req.arp_qos.txtp.traffic_class = ATM_UBR; for (i = optind+2; i < argc; i++) if (!strcmp(argv[i],"temp")) req.arp_flags &= ~ATF_PERM; + else if (!strcmp(argv[i],"pub")) req.arp_flags |= ATF_PUBL; else if (!strcmp(argv[i],"null")) req.arp_flags |= ATF_NULL; else if (!strcmp(argv[i],"arpsrv")) req.arp_flags |= ATF_ARPSRV; else if (!strcmp(argv[i],"pcr")) { @@ -159,7 +160,9 @@ if (*end) usage(argv[0]); } else usage(argv[0]); +#if 0 /* atmarpd now sets max_sdu if 0 */ req.arp_qos.txtp.max_sdu = RFC1483LLC_LEN+RFC1626_MTU; +#endif req.arp_qos.rxtp = req.arp_qos.txtp; if (text2atm(argv[optind+1],(struct sockaddr *) &req.arp_ha, sizeof(req.arp_ha),T2A_NAME) < 0) { diff -ur --new-file old/atm/ip/clip.c new/atm/ip/clip.c --- old/atm/ip/clip.c Wed Sep 4 12:10:58 1996 +++ new/atm/ip/clip.c Thu Sep 26 16:35:16 1996 @@ -54,7 +54,8 @@ qos.txtp.min_pcr = atoi(argv[2]); } qos.rxtp.traffic_class = ATM_UBR; - qos.txtp.max_sdu = qos.rxtp.max_sdu = RFC1626_MTU; + qos.txtp.max_sdu = qos.rxtp.max_sdu = RFC1626_MTU+ + (null ? 0 : RFC1483LLC_LEN); if (setsockopt(s,SOL_ATM,SO_ATMQOS,&qos,sizeof(qos)) < 0) { perror("setsockopt SO_ATMQOS"); return 1; diff -ur --new-file old/atm/lane/Makefile new/atm/lane/Makefile --- old/atm/lane/Makefile Mon Sep 9 20:36:43 1996 +++ new/atm/lane/Makefile Thu Sep 12 03:42:06 1996 @@ -14,6 +14,7 @@ # # SYSPGMS = les bus lecs +MAN8 = les.8 lecs.8 bus.8 LESBUSOBJS = mem.o load.o units.o load_lex.o timers.o dump.o atm.o \ events.o lane.o LESOBJS = $(LESBUSOBJS) packet.o connect.o db.c diff -ur --new-file old/atm/lane/bus.8 new/atm/lane/bus.8 --- old/atm/lane/bus.8 Thu Jan 1 01:00:00 1970 +++ new/atm/lane/bus.8 Thu Sep 12 03:47:25 1996 @@ -0,0 +1,2 @@ +.so man8/les.8 +.\"{{{}}} \ No newline at end of file diff -ur --new-file old/atm/lane/dump.c new/atm/lane/dump.c --- old/atm/lane/dump.c Thu Aug 8 23:21:56 1996 +++ new/atm/lane/dump.c Thu Sep 12 02:08:00 1996 @@ -52,8 +52,8 @@ /* Functions */ static const char* dump_opcode_text(unsigned short opcode); static const char* dump_status_text(unsigned short status); -static char* dump_maxframe(unsigned char size); -static char* dump_lantype(unsigned char lantype); +static const char* dump_maxframe(unsigned char size); +static const char* dump_lantype(unsigned char lantype); static void dump_atmtext(const AtmAddr_t addr); /* Initialize local data */ @@ -331,7 +331,7 @@ } } -static char* +static const char* dump_lantype(unsigned char lantype) { switch (lantype) { @@ -346,7 +346,7 @@ } } -static char* +static const char* dump_maxframe(unsigned char size) { switch (size) { diff -ur --new-file old/atm/lane/events.c new/atm/lane/events.c --- old/atm/lane/events.c Thu Aug 8 23:23:42 1996 +++ new/atm/lane/events.c Thu Sep 12 02:03:41 1996 @@ -226,7 +226,7 @@ case 0: /* Timeout */ timer_ack(&events_unit, soonest); - event_put(&events_unit, CE_TIMER, soonest->data); + event_put(&events_unit, CE_TIMER, (void*)soonest->data); break; default: /* Data arrival / SVC creation */ diff -ur --new-file old/atm/lane/lane.c new/atm/lane/lane.c --- old/atm/lane/lane.c Thu Aug 8 23:24:13 1996 +++ new/atm/lane/lane.c Thu Sep 12 02:13:39 1996 @@ -9,6 +9,7 @@ #include #include #include +#include /* Local includes */ #include "units.h" @@ -23,7 +24,8 @@ /* Local function prototypes */ static void main_init1(void); -static void parse_args(int argc, const char **argv); +static void main_release(void); +static void parse_args(int argc, char **argv); static void usage(void); static int dump_handler(const Event_t *event, void *funcdata); static int exit_handler(const Event_t *event, void *funcdata); @@ -35,10 +37,11 @@ NULL, main_init1, NULL, - NULL + main_release }; static const char *progname; +char *var_file = NULL; /* Functions */ @@ -52,9 +55,18 @@ Debug_unit(&main_unit, "Initialized."); } +static void +main_release(void) +{ + if (var_file) { + mem_free(&main_unit, var_file); + var_file = NULL; + } +} + /* Main loop */ int -main(int argc, const char **argv) +main(int argc, char **argv) { short do_restart = 0; const Event_t *event; @@ -156,70 +168,70 @@ exit(0); } -/* - * -dmodule sets debugging output of the module to true - * -mmodule sets memory debugging of the module to true - */ static void -parse_args(int argc, const char **argv) +parse_args(int argc, char **argv) { int i; const Unit_t *unit, **units; - const char *arg; - + progname = argv[0]; - for (i = 1; i < argc; i++) { - arg = argv[i]; - Debug_unit(&main_unit, "Arg %s", arg); - if (arg[0] == '-') { - switch (arg[1]) { - case 'd': - if (strcmp(&arg[2], "all") == 0) { - FOR_ALL_UNITS(units) { - set_var_bool(*units, "debug", BL_TRUE); - } + while(i!=-1) { + i = getopt(argc, argv, "d:m:f:"); + switch(i) { + case 'd': + if (strcmp(optarg, "all") == 0) { + FOR_ALL_UNITS(units) { + set_var_bool(*units, "debug", BL_TRUE); } - else { - unit = find_unit(&arg[2]); - if (unit != NULL) { - set_var_bool(unit, "debug", BL_TRUE); - } - else { - dump_printf(EL_ERROR, "Unknown module name: %s", &arg[2]); - usage(); - } + } else { + unit = find_unit(optarg); + if (unit) { + set_var_bool(unit, "debug", BL_TRUE); + } else { + dump_printf(EL_ERROR, "Unknown module name: %s", optarg); + usage(); } - break; - case 'm': - if (strcmp(&arg[2], "all") == 0) { - FOR_ALL_UNITS(units) { - set_var_bool(*units, "memdebug", BL_TRUE); - } + } + break; + case 'm': + if (strcmp(optarg, "all") == 0) { + FOR_ALL_UNITS(units) { + set_var_bool(*units, "memdebug", BL_TRUE); } - else { - unit = find_unit(&arg[2]); - if (unit != NULL) { - set_var_bool(unit, "memdebug", BL_TRUE); - } - else { - dump_printf(EL_ERROR, "Unknown module name: %s", &arg[2]); - usage(); - } + } else { + unit = find_unit(optarg); + if (unit) { + set_var_bool(unit, "memdebug", BL_TRUE); + } else { + dump_printf(EL_ERROR, "Unknown module name: %s", optarg); + usage(); } - break; - default: - usage(); - return; } + break; + case 'f': + var_file = mem_alloc(&main_unit, strlen(optarg)+1); + strcpy(var_file, optarg); + dump_printf(EL_NOTE, "Configuration file: %s\n", var_file); + break; + case -1: + break; + default: + usage(); + return; } } + if (!var_file) { + var_file = mem_alloc(&main_unit, strlen(DEFAULT_CFG_FILE)+1); + strcpy(var_file, DEFAULT_CFG_FILE); + dump_printf(EL_NOTE, "Configuration file: %s\n", var_file); + } } static void usage(void) { dump_printf(EL_ERROR, "Usage:"); - dump_printf(EL_ERROR, "%s [-dmodule]... [-mmodule]...", progname); + dump_printf(EL_ERROR, "%s [-d module]... [-m module]...[-f conf_file]", progname); exit(1); } diff -ur --new-file old/atm/lane/lane.h new/atm/lane/lane.h --- old/atm/lane/lane.h Thu Aug 8 23:24:26 1996 +++ new/atm/lane/lane.h Thu Sep 12 02:02:02 1996 @@ -83,7 +83,7 @@ unsigned reserved : 8; unsigned elan_name_size : 8; AtmAddr_t target_addr; - unsigned char elan_name[32]; + char elan_name[32]; } LaneControl_t; typedef struct { diff -ur --new-file old/atm/lane/lecs.8 new/atm/lane/lecs.8 --- old/atm/lane/lecs.8 Thu Jan 1 01:00:00 1970 +++ new/atm/lane/lecs.8 Thu Sep 12 04:01:02 1996 @@ -0,0 +1,103 @@ +.TH LES 8 "Sep 11, 1996" "Linux" "Maintenance Commands" +.SH NAME +les, bus \- ATM LAN Emulation service demons +.SH SYNOPSIS +.B lecs +.RB [ \-l\ \fIlisten_address\fP ] +.RB [ \-f\ \fIconfiguration_file\fP ] +.RB [ \-d\ ] +.SH DESCRIPTION +LE Service consists of three components: LAN Emulation Configuration +Server (\fBlecs\fP), LAN Emulation Server ( +\fBles(8)\fP) and Broadcast and Unknown Server (\fBbus(8)\fP). +.PP +\fBLecs\fP implements the distribution of LECs to different emulated +LANs. This is done by giving different LAN Emulation Server ATM addresses +to LECs. Distribution is based on \fBlecs\fP's configuration database +and information provided by the LE client. It is not required that a +\fBlecs\fP exists for all emulated LANs. It is possible to bypass this +configuration phase by directly telling ATM address of the \fBles(8)\fP to +the LEC. + +Configuration file example for \fBlecs\fP: +.in +2m +.nf +# Our ATM address (should be included to differentiate us from +# e.g. LEC) +# Must be before ELAN definitions +470023000000030300010002010020ea000ae905 + +# ELAN name is inside brackets. +# Parameters below are for Ethernet type LE (Linux & almost all +# other LE clients) +[tut-lane1] +# Address of the LES +LES:=470023000000030300010002010020ea000ae901 +# 802_3 or 802_5 (802_3 = Ethernet) +Type:=802_3 +# 1515, 4544, 9234 or 18190 (1516= Ethernet) +Max_Frame:=1516 + +# ATM address for hosts that are guided to this ELAN. +# Wildcard is x or X. +470023000000030300010002010020ea0005aax0 +470023000000030000010002010020ea0005bx00 +47.002300000003030001000201.00603E2FDX23.00 +470023000000030300010002010020ea000Xxx00 +DEFAULT +# Another ELAN, which has empty name +[asdf] +# This directive sets this elan as the default i.e. it will be +# included if LEC's configure request could not be matched to +# other ELANs +#DEFAULT +LES= 470023000000030300010002010020ea000ae902 +Type=Ethernet +.DT +.fi +.in + +Rules for finding ELAN definitions using information provided in +LE_CONFIGURE_REQUEST and the configuration file are as follows: +.PP + +.in +2m +.nf +1. Find an entry where ELAN-NAME matches exactly and an + ATM address of the LEC is found in ELAN definition. + These are to match exactly with the information given in + LE_CONFIGURE_REQUEST. If ELAN-NAME is found, but ATM + address doesn't match then reject with reason "Permission + denied". +2. Search for first ELAN which matches in type of emulated LAN, + maximum frame size and ATM address of the LEC. +3. If matching ELAN was not found, return default ELAN + definitions. +4. No match, so request is rejected with reason "No + Configuration". +.PP +.DT +.fi +.in +\fBSIGHUP\fP restarts the server. +.SH OPTIONS +.TP +.IP \fB\-d\fP +Reads the configuration file, dumps its contents and exits. +.IP \fB\-l\ \fIlisten_address\fP +Use the \fIlisten_address\fP to where wait connections. +.IP \fB\-f\ \fIconfiguration_file\fP +Use the specified configuration file instead of \fB.lecs_conf\fP. +.SH FILES +.PD 0 +.TP 25 +.B .lecs_conf +configuration file +.PD +.SH BUGS +Undocumented. +.SH AUTHOR +Marko Kiiskila, TUT +.SH "SEE ALSO" +les(8), atmsigd(8), zeppelin(8) +.\"{{{}}} diff -ur --new-file old/atm/lane/lecs.c new/atm/lane/lecs.c --- old/atm/lane/lecs.c Sun Aug 18 22:20:48 1996 +++ new/atm/lane/lecs.c Thu Sep 12 02:20:41 1996 @@ -43,10 +43,12 @@ extern int errno; +#define DUMP_PACKETS 0 + static void usage(const char *progname) { - printf("Usage: %s [-f configuration_file][-l listen_address][-d dump db]\n", + printf("Usage: %s [-f configuration_file][-l listen_address][-d]\n", progname); } @@ -68,6 +70,9 @@ LaneControl_t *dp; Elan_t *elan; unsigned short response; +#ifdef DUMP_PACKETS + int i; +#endif if (len < sizeof(LaneControl_t)) return -1; @@ -93,6 +98,12 @@ dp->elan_name_size = elan->elan_name_size; memcpy(dp->target_atm, elan->les_addr, ATM_ESA_LEN); } +#ifdef DUMP_PACKETS + for(i=0;i +.SH "SEE ALSO" +lecs(8), atmsigd(8), zeppelin(8) +.\"{{{}}} diff -ur --new-file old/atm/lane/load.c new/atm/lane/load.c --- old/atm/lane/load.c Thu Aug 8 23:24:43 1996 +++ new/atm/lane/load.c Thu Sep 12 02:02:50 1996 @@ -63,7 +63,7 @@ static const char *rcsid = "$Id: load.c,v 1.17 1995/07/02 17:55:16 carnil Exp $"; static VarList_t *varlist; -static const char *var_file = ".lanevars"; +extern char *var_file; const Unit_t load_unit = { "load", diff -ur --new-file old/atm/lane/load.h new/atm/lane/load.h --- old/atm/lane/load.h Thu Aug 8 23:25:04 1996 +++ new/atm/lane/load.h Thu Sep 12 02:03:48 1996 @@ -36,7 +36,8 @@ void dump_vars(const Unit_t *unit); /* Global data */ -extern const Unit_t load_unit; +#define DEFAULT_CFG_FILE ".lanevars" +extern const Unit_t load_unit; #endif diff -ur --new-file old/atm/lane/timers.c new/atm/lane/timers.c --- old/atm/lane/timers.c Thu Aug 8 23:26:51 1996 +++ new/atm/lane/timers.c Thu Sep 12 02:02:58 1996 @@ -165,7 +165,7 @@ /* Delay for the specified period */ void -timer_alarm(const Unit_t *unit, Timer_t *timer, unsigned int nsecs, const void *data) +timer_alarm(const Unit_t *unit, Timer_t *timer, unsigned int nsecs, void *data) { assert (timer != NULL); timer->data = data; diff -ur --new-file old/atm/lane/timers.h new/atm/lane/timers.h --- old/atm/lane/timers.h Thu Aug 8 23:27:04 1996 +++ new/atm/lane/timers.h Thu Sep 12 02:03:01 1996 @@ -18,13 +18,14 @@ typedef struct { const Unit_t *unit; unsigned int alarm_time; - const void *data; + void *data; } Timer_t; /* Global function prototypes */ Timer_t *timer_new(const Unit_t *unit); void timer_free(const Unit_t *unit, Timer_t *timer); -void timer_alarm(const Unit_t *unit, Timer_t *timer, unsigned int nsecs, const void *data); +void timer_alarm(const Unit_t *unit, Timer_t *timer, unsigned int nsecs, + void *data); void timer_ack(const Unit_t *unit, Timer_t *timer); Timer_t *timer_find_soonest(const Unit_t *unit); diff -ur --new-file old/atm/led/Makefile new/atm/led/Makefile --- old/atm/led/Makefile Mon Sep 2 19:41:25 1996 +++ new/atm/led/Makefile Tue Sep 17 04:35:24 1996 @@ -2,7 +2,7 @@ OBJS=lec_arp.o lec_ctrl.o le_disp.o g_event.o \ utils.o timers.o address.o conn.o main.o kernel_itf.o BOOTPGMS=zeppelin -MAN8= +MAN8= zeppelin.8 CFLAGS_PRIVATE=-ansi -pedantic include ../Rules.make diff -ur --new-file old/atm/led/address.c new/atm/led/address.c --- old/atm/led/address.c Fri Aug 16 12:55:54 1996 +++ new/atm/led/address.c Tue Sep 17 03:09:31 1996 @@ -147,8 +147,15 @@ client = (Client_t *)client_handle; - client->notify=1; - addr_reg_timer_callback((HANDLE)client); + if (ATM_EQUAL_NULL(client->addr)) { + client->notify=1; + addr_reg_timer_callback((HANDLE)client); + } else { + client->notify=0; + client->callback(client->callback_handle,&client->addr, + ADDR_REG_EVENT_ATM_ADDR_ALLOCATED); + addr_reg_timer_callback((HANDLE)client); + } return STATUS_K_SUCCESS; } @@ -173,6 +180,7 @@ Client_t *client = Clientlist; ATM_COPY(*set_to, client->addr); + EVENT(EM_DEBUG,("Addr_set_atm_addr %s\n",disp_atm_text(client->addr))); } int @@ -296,8 +304,7 @@ client->addr.esi[2] == ouraddr->sas_addr.prv[15] && client->addr.esi[3] == ouraddr->sas_addr.prv[16] && client->addr.esi[4] == ouraddr->sas_addr.prv[17] && - client->addr.esi[5] == ouraddr->sas_addr.prv[18] && - client->addr.sel == ouraddr->sas_addr.prv[19]) { + client->addr.esi[5] == ouraddr->sas_addr.prv[18]) { /*...and has stayed same*/ mem_free(EINST, buffer); return; diff -ur --new-file old/atm/led/cm_sap.h new/atm/led/cm_sap.h --- old/atm/led/cm_sap.h Fri Aug 9 14:13:10 1996 +++ new/atm/led/cm_sap.h Tue Sep 17 06:47:12 1996 @@ -412,6 +412,7 @@ SAP_CONNECT_CALLBACK svc_connect_callback, SAP_LINK_STATUS_CALLBACK link_status_callback, SAP_XMT_DONE_CALLBACK xmt_done_callback, + int itf_num, const char *p_sap_text, HANDLE *p_sap_handle); diff -ur --new-file old/atm/led/conn.c new/atm/led/conn.c --- old/atm/led/conn.c Sat Aug 31 14:18:21 1996 +++ new/atm/led/conn.c Tue Sep 17 06:55:43 1996 @@ -120,6 +120,7 @@ unsigned long rcv_packet_count; unsigned long accept_packet_count; unsigned long reject_packet_count; + int itf_num; struct _Sap_client_t_ *next; } Sap_client_t; @@ -140,6 +141,7 @@ SAP_CONNECT_CALLBACK svc_connect_callback, SAP_LINK_STATUS_CALLBACK link_status_callback, SAP_XMT_DONE_CALLBACK xmt_done_callback, + int itf_num, const char *p_sap_text, HANDLE *p_sap_handle) { Sap_client_t *client; @@ -179,6 +181,8 @@ /* Statistic variables */ client->xmt_packet_count = client->rcv_packet_count = client->accept_packet_count = client->reject_packet_count = 0; + + client->itf_num = itf_num; /* Link to place */ client->next = clientlist; @@ -278,6 +282,7 @@ HANDLE *p_conn_handle) { Conn_t *conn; + Sap_client_t *sap = (Sap_client_t *)sap_handle; int s; int ret; struct sockaddr_atmsvc us; @@ -426,12 +431,12 @@ return STATUS_K_ATM_RESOURCES; } - /* Notify lower layer. */ switch (p_conn_info->blli.l3.tr9577.snap[4]) { /* AAAAAARRRGGHHH! */ case 0x02: case 0x03: memcpy(ioc_data.atm_addr, p_conn_info->addr.sas_addr.prv, ATM_ESA_LEN); + ioc_data.dev_num = sap->itf_num; ioc_data.receive = 0; EVENT(EM_DEBUG,("About to ioctl(s, ATMLEC_DATA, &ioc_data)\n")); if (ioctl(s, ATMLEC_DATA, &ioc_data)<0) { @@ -439,7 +444,7 @@ strerror(errno))); if (is_data_direct(p_conn_info)) { /* Try to remove possible entry in kernel */ - lc_addr_delete(conn_context, p_conn_info->addr.sas_addr.prv); + lc_addr_delete(conn_context, p_conn_info->addr.sas_addr.prv); } close(s); *p_conn_handle = NULL; @@ -449,7 +454,7 @@ break; case 0x04: case 0x05: - if (ioctl(s, ATMLEC_MCAST)<0) { + if (ioctl(s, ATMLEC_MCAST, sap->itf_num)<0) { EVENT(EM_SERR,("Can't change socket into LE mcast socket:%s\n", strerror(errno))); if (is_data_direct(p_conn_info)) { @@ -803,7 +808,7 @@ ioc_data.receive = 0; /* Data direct */ } else ioc_data.receive = 2; /* Multicast distribute */ - + ioc_data.dev_num = sap->itf_num; EVENT(EM_DEBUG,("About to ioctl(fd, ATMLEC_DATA, &ioc_data)\n")); if (ioctl(fd, ATMLEC_DATA, &ioc_data)<0) { EVENT(EM_SERR,("Can't change socket into LE data socket:%s\n", diff -ur --new-file old/atm/led/kernel_itf.c new/atm/led/kernel_itf.c --- old/atm/led/kernel_itf.c Tue Aug 6 16:33:07 1996 +++ new/atm/led/kernel_itf.c Tue Sep 17 06:51:37 1996 @@ -56,7 +56,7 @@ static kernel_callback callback_funcs[ATMLEC_MSG_TYPE_MAX]; int -kernel_init(unsigned char *mac_addr) +kernel_init(unsigned char *mac_addr, int itf_num) { int rvalue; struct atmlec_msg msg; @@ -67,8 +67,8 @@ EVENT(EM_SERR,("Socket creation failure:%s\n",strerror(errno))); return -1; } - rvalue = ioctl(lec_socket, ATMLEC_CTRL); - if (rvalue <0) { + itf_num = ioctl(lec_socket, ATMLEC_CTRL, itf_num); + if (itf_num <0) { EVENT(EM_SERR,("Socket ioctl to lecd_ctrl failed:%s\n", strerror(errno))); close(lec_socket); return -1; @@ -104,7 +104,7 @@ return -1; } /* Add fd to select */ - return 0; + return itf_num; } int @@ -156,8 +156,6 @@ return "SVC_SETUP"; case l_arp_xmt: return "ARP_XMT"; - case l_add_permanent: - return "ADD_PERMANENT"; case l_addr_delete: return "ADDR_DELETE"; case l_topology_change: @@ -166,8 +164,6 @@ return "FLUSH_COMPLETE"; case l_arp_update: return "ARP_UPDATE"; - case l_reset: - return "RESET"; case l_config: return "CONFIG"; default: diff -ur --new-file old/atm/led/kernel_itf.h new/atm/led/kernel_itf.h --- old/atm/led/kernel_itf.h Tue Aug 6 16:33:08 1996 +++ new/atm/led/kernel_itf.h Tue Sep 17 06:42:21 1996 @@ -33,7 +33,7 @@ typedef void (*kernel_callback)(struct atmlec_msg *mesg); -int kernel_init(unsigned char *mac_addr); +int kernel_init(unsigned char *mac_addr, int itf_num); int kernel_sendmsg(atmlec_msg_type type, unsigned char *mac_addr, unsigned char *atm_addr, struct atmlec_config_msg *config, unsigned long flag); diff -ur --new-file old/atm/led/lec_arp.c new/atm/led/lec_arp.c --- old/atm/led/lec_arp.c Tue Aug 20 20:39:34 1996 +++ new/atm/led/lec_arp.c Tue Sep 17 05:22:28 1996 @@ -229,14 +229,6 @@ } STATUS -la_perm_add(HANDLE la_elan_handle, ESI esi, ADDR_ATM addr_atm) -{ - kernel_sendmsg(l_add_permanent, (unsigned char *)esi, - (unsigned char*)&addr_atm, NULL, 0); - return STATUS_K_SUCCESS; -} - -STATUS la_addr_delete(HANDLE la_elan_handle, unsigned char *atm_addr, BOOLEAN permanent) diff -ur --new-file old/atm/led/lec_arp.h new/atm/led/lec_arp.h --- old/atm/led/lec_arp.h Tue Aug 6 16:33:08 1996 +++ new/atm/led/lec_arp.h Tue Sep 17 05:22:20 1996 @@ -74,7 +74,6 @@ * - la_register * - la_config * - la_arp_resolve -* - la_perm_add * - la_addr_delete * - la_arp_update * - la_flush_complete @@ -100,10 +99,6 @@ * made once the configuration phase of the join is * complete and the parameters are known. * -* la_perm_add.............Permanent addresses may be added to the cache by -* local or remote (via SNMP) network management -* applications. -* * la_arp_resolve..........This is called each time a transmit data packet is * sent by the protocol. In this case, the * destination MAC address is not in the LE-ARP cache @@ -470,39 +465,6 @@ * The arp cache is empty. --*/ void la_elan_reset (HANDLE la_elan_handle); - -/*++ -* =============== -* = la_perm_add = -* =============== -* -* Overview: -* Add a permanent LE-ARP cache entry. Such an entry does not age and is -* kept until this ELAN instance is deregietered via la_deregister. -* Permanent LE-ARP cache entries are added and deleted at the request of -* network management software. -* -* Arguments: -* la_elan_handle - (IN) Handle returned by la_register. -* esi - (IN) MAC address of the permanent entry. -* addr_atm - (IN) ATM address related to the MAC address. -* -* Returns: -* STATUS_K_SUCCESS - Successful Completion, see postconditions. -* STATUS_K_RESOURCES - Insufficient resources to complete operation. -* STATUS_K_BUSY - A matching permanent address is already in the cache. -* -* Preconditions: -* None -* -* Postconditions: -* There is a permanent address with the requested mapping in the LE-ARP -* cache. If there was a non-permanent entry with the requested MAC address, -* that entry is overwritten with the new permanent entry. ---*/ -STATUS la_perm_add (HANDLE la_elan_handle, - ESI esi, - ADDR_ATM addr_atm); /*++ * ================== diff -ur --new-file old/atm/led/main.c new/atm/led/main.c --- old/atm/led/main.c Tue Aug 20 20:41:40 1996 +++ new/atm/led/main.c Tue Sep 17 06:57:21 1996 @@ -257,7 +257,7 @@ static void usage(const char *progname) { - printf("Usage: %s [-c LECS_address]|[-s LES_address] [-e esi] [-n VLAN_name] [-m mesg_mask]\n",progname); + printf("Usage: %s [-c LECS_address]|[-s LES_address] [-e esi] [-n VLAN_name] [-m mesg_mask][-i interface_number]\n",progname); } static int @@ -313,9 +313,10 @@ struct timeval *timeout; HANDLE current_timer; ADDR_ATM *listen_address = NULL; + int itf_num = 0; while(poll_ret != -1) { - poll_ret = getopt(argc, argv, "c:e:n:s:m:l:"); + poll_ret = getopt(argc, argv, "c:e:n:s:m:l:i:"); switch(poll_ret) { case 'c': if (atm_set) { @@ -375,6 +376,14 @@ } EVENT(EM_MSG,("Our ATM address: %s\n", disp_atm_text(*listen_address))); break; + case 'i': + if (sscanf(optarg, "%d",&itf_num)<0 || itf_num >= MAX_LEC_ITF) { + EVENT(EM_SERR,("Invalid interface number\n")); + usage(argv[0]); + exit(-1); + } + EVENT(EM_MSG,("Interface number set to %d\n",itf_num)); + break; case -1: break; default: @@ -412,10 +421,10 @@ utl_list_init (p_context->elan_list); - if (kernel_init(mac_addr)<0) { + if ((itf_num=kernel_init(mac_addr, itf_num))<0) { EVENT(EM_SERR,("Kernel interface creation failed, exiting...\n")); return STATUS_K_RESOURCES; - } + } /* Create an instance of the LEC_CTRL module. If there is an error, back * out of our previous operations and return failure status. @@ -503,6 +512,7 @@ lc_sap_connect, lc_sap_link_status, ld_xmt_done_callback, + itf_num, "LAN Emulation Convergence", &p_elan->sap_handle); if (status != STATUS_K_SUCCESS) { diff -ur --new-file old/atm/led/zeppelin.8 new/atm/led/zeppelin.8 --- old/atm/led/zeppelin.8 Thu Jan 1 01:00:00 1970 +++ new/atm/led/zeppelin.8 Tue Sep 17 05:34:25 1996 @@ -0,0 +1,61 @@ +.TH zeppelin 8 "Sep 17, 1996" "Linux" "Maintenance Commands" +.SH NAME +zeppelin \- ATM LAN Emulation client demon (LED) Zeppelin +.SH SYNOPSIS +.B zeppelin +.RB [ \-c\ \fILECS_address\fP ] | +.RB [ \-s\ \fILES_address\fP ] +.RB [ \-e\ \fIesi\fP ] +.RB [ \-n\ \fIVLAN_name\fP ] +.RB [ \-m\ \fImesg_mask\fP ] +.RB [ \-i\ \fIinterface_number\fP ] +.SH DESCRIPTION +A LAN Emulation Client is an entity in an ATM endstation that performs +data forwarding, address resolution and other control functions. It +uses the LUNI interface when communicating with other components in +emulated LANs. It provides upper protocol layers a MAC like +interface similar to IEEE 802.3/Ethernet or IEEE 802.5/Token Ring LAN. +.PP +LAN Emulation client code is divided into two parts: user space +application LAN Emulation Demon called (LED) \fBzeppelin(8)\fP, and the +kernel component. \fBZeppelin\fP is responsible for control operations needed +in LAN Emulation clienthood. It forms the necessary VCCs and receives +all the LE control frames and acts accordingly. It also controls the +operation of the LEC kernel component. +.PP +Linux LEC supports only Ethernet type of emulated LAN. +.PP +\fBSIGHUP\fP causes restart of the LEC. All resources are +released and \fBzeppelin\fP is started. +.SH OPTIONS +.TP +.IP \fB\-c\ \fILECS_address\fP +ATM address of \fBlecs(8)\fP (Lan Emulation Configuration Server), if not +set, Well-Known server address is used. +.IP \fB\-s\ \fILES_address\fP +ATM address of \fBles(8)\fP (Lan Emulation Server), can be used in +bypassing configuration phase in joining emulated Lan i.e \fBlecs\fP address +is not used. +.IP \fB\-e\ \fIesi\fP +Mac address to use when communicating in Emulated LAN. E.g. 00:20:22:23:04:05 . +.IP \fB\-n\ \fIVLAN_name\fP +Name of the virtual LAN to which joining is requested. +This is used in LE_CONFIGURE_REQUEST to LECS or +LE_JOIN_RESPONSE to LES, if configuration phase is bypassed. +.IP \fB\-m\ \fImesg_mask\fP +Sometimes one wants to know more what is happening in LE +daemon e.g. when nothing works. This is a hexadecimal long value +setting global message mask. 0 = No messages, ffff = All messages. +.IP \fB\-i\ \fIinterface_number\fP +Linux LEC supports up to 4 network interfaces. This number tells +zeppelin to which of these to attach. Network interfaces are +numbered from "lec0" to "lec3". +.SH BUGS +Supports only IEEE 802.3 / Ethernet type of ELANs. +.PP +John Bonham died 1980 and Led Zeppelin broke. +.SH AUTHOR +Marko Kiiskila, TUT +.SH "SEE ALSO" +lecs(8), atmsigd(8), les(8) +.\"{{{}}} diff -ur --new-file old/atm/lib/Makefile new/atm/lib/Makefile --- old/atm/lib/Makefile Tue Jun 4 23:17:54 1996 +++ new/atm/lib/Makefile Fri Sep 27 21:56:40 1996 @@ -1,5 +1,5 @@ ATM_OBJS=text2atm.o atm2text.o atmequal.o sdu2cell.o -ATMD_OBJS=common.o diag.o queue.o timer.o +ATMD_OBJS=common.o diag.o timer.o AQ_OBJS=arequipa.o PGMS=#test GENLIBS=libatm.a libatmd.a libarequipa.a diff -ur --new-file old/atm/lib/arequipa.c new/atm/lib/arequipa.c --- old/atm/lib/arequipa.c Wed Jul 31 15:47:49 1996 +++ new/atm/lib/arequipa.c Fri Sep 27 22:20:12 1996 @@ -26,9 +26,9 @@ } a = *addr; if (a.sas_family == AF_ATMSVC) { - a.sas_addr.bhli.hl_type = ATM_HL_USER; - a.sas_addr.bhli.hl_length = strlen("AREQ"); - strcpy(a.sas_addr.bhli.hl_info,"AREQ"); + a.sas_addr.bhli.hl_type = ATM_HL_VENDOR; + a.sas_addr.bhli.hl_length = 7; + memcpy(a.sas_addr.bhli.hl_info,AREQUIPA_HLT_VS_ID,7); a.sas_addr.blli = &blli; blli.l2_proto = ATM_L2_ISO8802; blli.l3_proto = ATM_L3_NONE; diff -ur --new-file old/atm/lib/atmd.h new/atm/lib/atmd.h --- old/atm/lib/atmd.h Thu May 9 16:01:40 1996 +++ new/atm/lib/atmd.h Thu Sep 26 18:15:18 1996 @@ -60,34 +60,6 @@ void diag(const char *component,int severity,const char *fmt,...); -/*----------- Quick and very very dirty buffer and queue handling -----------*/ - - -typedef struct _buffer { - void *data; - int length; - int key; /* SD.N(S) */ - int extra; /* SD.N(PS) */ - struct _buffer *next,*prev; -} BUFFER; - -typedef struct { - BUFFER *first,*last; -} QUEUE; - - -BUFFER *buffer_create(int length,int key); -BUFFER *buffer_clone(BUFFER *b); -void buffer_discard(BUFFER *b); -void queue_init(QUEUE *q); -void queue_put(QUEUE *q,BUFFER *b); -void queue_remove(QUEUE *q,BUFFER *b); -BUFFER *queue_peek(QUEUE *q); -BUFFER *queue_get(QUEUE *q); -BUFFER *queue_lookup(QUEUE *q,int key); -void queue_clear(QUEUE *q); - - /*------------------------------ Timer support ------------------------------*/ diff -ur --new-file old/atm/lib/diag.c new/atm/lib/diag.c --- old/atm/lib/diag.c Wed Sep 4 20:07:56 1996 +++ new/atm/lib/diag.c Fri Sep 27 21:57:19 1996 @@ -80,6 +80,9 @@ } +void diag_fatal_debug_hook(void); /* GCC insists on a prototype */ + + void diag_fatal_debug_hook(void) { /* diff -ur --new-file old/atm/lib/queue.c new/atm/lib/queue.c --- old/atm/lib/queue.c Fri Oct 20 17:20:39 1995 +++ new/atm/lib/queue.c Thu Jan 1 01:00:00 1970 @@ -1,97 +0,0 @@ -/* queue.c - Quick and very very dirty buffer and queue handling */ - -/* Written 1995 by Werner Almesberger, EPFL-LRC */ - - -#include -#include - -#include "atmd.h" - - -BUFFER *buffer_create(int length,int key) -{ - BUFFER *buf; - - buf = alloc_t(BUFFER); - buf->data = alloc(length); - buf->length = length; - buf->key = key; - return buf; -} - - -BUFFER *buffer_clone(BUFFER *b) -{ - BUFFER *buf; - - buf = buffer_create(b->length,b->key); - memcpy(buf->data,b->data,b->length); - return buf; -} - - -void buffer_discard(BUFFER *b) -{ - free(b->data); - free(b); -} - - -void queue_init(QUEUE *q) -{ - q->first = q->last = NULL; -} - - -void queue_put(QUEUE *q,BUFFER *b) -{ - Q_INSERT_AFTER(q->first,b,q->last); - q->last = b; -} - - -void queue_remove(QUEUE *q,BUFFER *b) -{ - if (q->last == b) q->last = b->prev; - Q_REMOVE(q->first,b); -} - - -BUFFER *queue_peek(QUEUE *q) -{ - return q->first; -} - - -BUFFER *queue_get(QUEUE *q) -{ - BUFFER *buf; - - buf = queue_peek(q); - if (buf) queue_remove(q,buf); - return buf; -} - - -BUFFER *queue_lookup(QUEUE *q,int key) -{ - BUFFER *walk; - - for (walk = q->first; walk; walk = walk->next) - if (walk->key == key) break; - return walk; -} - - -void queue_clear(QUEUE *q) -{ - BUFFER *next; - - while (q->first) { - next = q->first->next; - buffer_discard(q->first); - q->first = next; - } - q->last = NULL; -} diff -ur --new-file old/atm/maint/atmaddr.c new/atm/maint/atmaddr.c --- old/atm/maint/atmaddr.c Mon Mar 11 13:07:54 1996 +++ new/atm/maint/atmaddr.c Thu Sep 26 18:13:32 1996 @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -64,6 +65,7 @@ if (argc < 3 || argc > 4) usage(name); if (argc == 4) itf = argv[2]; cmd = argv[1][1] == 'a' ? ATM_ADDADDR : ATM_DELADDR; + memset(&addr,0,sizeof(addr)); if (text2atm(argv[argc-1],(struct sockaddr *) addr, sizeof(*addr),T2A_SVC | T2A_NAME) < 0) usage(name); break; diff -ur --new-file old/atm/maint/atmdump.8 new/atm/maint/atmdump.8 --- old/atm/maint/atmdump.8 Thu Nov 23 15:46:45 1995 +++ new/atm/maint/atmdump.8 Thu Sep 26 18:50:42 1996 @@ -1,9 +1,9 @@ -.TH ATMDUMP 8 "Nov 23, 1995" "Linux" "Maintenance Commands" +.TH ATMDUMP 8 "Sep 26, 1996" "Linux" "Maintenance Commands" .SH NAME atmdump \- capture or generate ATM cells .SH SYNOPSIS -.ad l .B atmdump +.RB [ \-i ] .RB [\ \-t\ \fItype\fB .RB [ \-g\ \fIgfc\fB ] .RB [ \-c ] @@ -19,6 +19,10 @@ In both modes of operation, the interface number, the VPI, and the VCI have to be specified. .SH OPTIONS +.IP \fB\-i\fP +displays timestamps as the interval since the last cell reception. By +default, the absolute time is displayed. This options is ignored in +transmit mode. .IP \fB\-t\ \fItype\fP selects transmit mode and specifies the payload type. A list of valid payload type numbers can be obtained by invoking diff -ur --new-file old/atm/maint/atmdump.c new/atm/maint/atmdump.c --- old/atm/maint/atmdump.c Sat Aug 31 14:18:32 1996 +++ new/atm/maint/atmdump.c Fri Sep 27 15:00:20 1996 @@ -20,17 +20,41 @@ "Data SDU 1, CE","Segment OAM F5","End-to-end OAM F5","Reserved (RM)", "Reserved" }; +static int interval = 0; /* display absolute time by default */ + #define GET(item) ((*cell & ATM_HDR_##item##_MASK) >> ATM_HDR_##item##_SHIFT) static void analyze(unsigned long *cell,struct timeval stamp) { + static struct timeval last; + static int first = 1; int i; - printf("%d.%06d: VPI=%ld VCI=%ld, GFC=0x%lx, CLP=%ld, %s (PTI %ld)\n", - stamp.tv_sec,stamp.tv_usec,GET(VPI),GET(VCI),GET(GFC), - *cell & ATM_HDR_CLP,pti[GET(PTI)],GET(PTI)); + if (first || !interval) { + printf("%2d:%02d:%02d",(stamp.tv_sec/3600) % 24,(stamp.tv_sec/60) % 60, + stamp.tv_sec % 60); + if (interval) { + first = 0; + last = stamp; + } + } + else { + struct timeval diff; + + diff.tv_sec = stamp.tv_sec-last.tv_sec; + diff.tv_usec = stamp.tv_usec-last.tv_usec; + while (diff.tv_usec < 0) { + diff.tv_usec += 1000000; + diff.tv_sec--; + } + last = stamp; + printf("%8d",diff.tv_sec); + } + printf(".%06d: VPI=%ld VCI=%ld, GFC=0x%lx, CLP=%ld, %s (PTI %ld)\n", + stamp.tv_usec,GET(VPI),GET(VCI),GET(GFC),*cell & ATM_HDR_CLP, + pti[GET(PTI)],GET(PTI)); for (i = 0; i < ATM_CELL_PAYLOAD; i++) { if (!(i & 15)) printf(" "); printf("%02x ",((unsigned char *) cell)[i+4]); @@ -43,8 +67,8 @@ { int i; - fprintf(stderr,"usage: %s [ -t type [ -g gfc ] [ -c ] ] [itf.]vpi.vci\n", - name); + fprintf(stderr,"usage: %s [ -i ] [ -t type [ -g gfc ] [ -c ] ] " + "[itf.]vpi.vci\n",name); for (i = 0; i < 8; i++) fprintf(stderr," %-6s %d %s\n",i ? "" : "type",i,pti[i]); fprintf(stderr," gfc 0-15, default 0\n"); @@ -66,6 +90,9 @@ name = argv[0]; while ((c = getopt(argc,argv,"t:g:c")) != EOF) switch (c) { + case 'i': + interval = 1; + break; case 't': type = strtol(optarg,&end,0); if (*end || type < 0 || type > 7) usage(name); diff -ur --new-file old/atm/maint/zntune.c new/atm/maint/zntune.c --- old/atm/maint/zntune.c Tue Jul 30 22:35:01 1996 +++ new/atm/maint/zntune.c Thu Sep 26 20:43:30 1996 @@ -1,4 +1,4 @@ -/* zntune.c - ZN1221 free buffer pool tuning */ +/* zntune.c - ZN122x free buffer pool tuning */ /* Written 1995,1996 by Werner Almesberger, EPFL-LRC */ @@ -11,6 +11,7 @@ #include #include +#include /* for struct timeval, although it's not used */ #include "/usr/src/linux/drivers/atm/zatm.h" diff -ur --new-file old/atm/mkdist new/atm/mkdist --- old/atm/mkdist Wed Sep 4 19:58:48 1996 +++ new/atm/mkdist Fri Sep 27 23:24:00 1996 @@ -24,7 +24,8 @@ atm/sigd/sap.h atm/sigd/sap.c atm/sigd/trace.c atm/sigd/trace.h \ 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/sscf.c atm/saal/sscop.h atm/saal/sscop.c atm/saal/queue.h \ + atm/saal/queue.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 \ @@ -62,10 +63,10 @@ atm/test/bw.c atm/test/ttcp.c atm/test/aping.c \ atm/ip/Makefile atm/ip/atmarp.c atm/ip/clip.c atm/ip/clip.8 atm/ip/atmarp.8 \ atm/debug/Makefile atm/debug/ed.c atm/debug/encopy.c atm/debug/endump.c \ - atm/debug/peek.pl atm/debug/zndump.c \ + atm/debug/peek.pl atm/debug/zndump.c atm/debug/znth.c \ atm/lib/Makefile atm/lib/atm2text.c atm/lib/atm.h atm/lib/text2atm.c \ atm/lib/atmequal.c atm/lib/sdu2cell.c \ - atm/lib/atmd.h atm/lib/common.c atm/lib/diag.c atm/lib/queue.c \ + atm/lib/atmd.h atm/lib/common.c atm/lib/diag.c \ atm/lib/timer.c atm/lib/arequipa.h atm/lib/arequipa.c \ atm/led/USAGE atm/led/COPYRIGHT.DEC atm/led/COPYRIGHT.TUT \ atm/led/lec.h atm/led/lec_arp.h atm/led/lec_ctrl.h atm/led/emask.h \ @@ -77,14 +78,16 @@ atm/led/conn.h atm/led/lec_arp.c atm/led/lec_ctrl.c \ atm/led/le_disp.c atm/led/g_event.c atm/led/utils.c atm/led/timers.c \ atm/led/address.c atm/led/conn.c atm/led/main.c atm/led/kernel_itf.c \ - atm/led/Makefile \ - atm/lane/COPYRIGHT.TUT atm/lane/Makefile atm/lane/USAGE atm/lane/atm.c \ + atm/led/Makefile atm/led/zeppelin.8 \ + atm/lane/COPYRIGHT.TUT atm/lane/Makefile atm/lane/USAGE \ + atm/lane/bus.8 atm/lane/lecs.8 atm/lane/les.8 \ + atm/lane/atm.c \ atm/lane/atm.h atm/lane/atm_lecs.c atm/lane/atm_lecs.h \ atm/lane/connect.c atm/lane/connect.h atm/lane/connect_bus.c \ atm/lane/db.c atm/lane/db.h atm/lane/dump.c atm/lane/dump.h \ atm/lane/events.c atm/lane/events.h atm/lane/lane.c atm/lane/lane.h \ atm/lane/ldb.c atm/lane/ldb.h atm/lane/lecs.c atm/lane/lecs.h \ - atm/lane/lecs_db.h atm/lane/lecs_db.h atm/lane/lecs_db.l \ + atm/lane/lecs_db.h atm/lane/lecs_db.l \ atm/lane/lecs_load.c atm/lane/lecs_load.h atm/lane/load.c atm/lane/load.h \ atm/lane/load_lex.h atm/lane/load_lex.l atm/lane/mem.c atm/lane/mem.h \ atm/lane/mem_lecs.c atm/lane/mem_lecs.h atm/lane/packet.c \ diff -ur --new-file old/atm/qgen/Makefile new/atm/qgen/Makefile --- old/atm/qgen/Makefile Sat Aug 31 14:52:39 1996 +++ new/atm/qgen/Makefile Fri Sep 27 21:55:24 1996 @@ -36,9 +36,9 @@ q.test: q.test.c qtest.c $(CC) $(CFLAGS) -o q.test $(STANDARDS) q.test.c -q.dump: qd.dump.c qd.out.c qlib.h qlib.c +q.dump: qd.dump.c q.out.h qd.out.c qlib.h qlib.c $(CC) $(CFLAGS) -DSTANDALONE -o q.dump \ - $(STANDARDS) qd.dump.c + $(STANDARDS) qd.dump.c common.o qd.dump.o: qd.dump.c qd.out.c qlib.h qlib.c $(CC) $(CFLAGS) -c $(STANDARDS) qd.dump.c diff -ur --new-file old/atm/qgen/op.h new/atm/qgen/op.h --- old/atm/qgen/op.h Tue Jan 30 20:40:08 1996 +++ new/atm/qgen/op.h Fri Sep 27 20:56:14 1996 @@ -27,7 +27,9 @@ #define OP_CASE 9 /* case ,,,, { , ,,... { ,...,jump }, ... } */ #define OP_IFEND 10 /* ifend */ - -#define OP_DUMP 11 /* dump */ +#define OP_DUMP 11 /* dump ; dumper only */ +#define OP_BEGIN_REC 12 /* begin_recovery ,, */ +#define OP_END_REC 13 /* end_recovery */ +#define OP_ABORT 14 /* abort */ #endif diff -ur --new-file old/atm/qgen/q2931.h new/atm/qgen/q2931.h --- old/atm/qgen/q2931.h Sat Aug 31 14:27:33 1996 +++ new/atm/qgen/q2931.h Fri Sep 27 20:16:26 1996 @@ -301,4 +301,12 @@ #define ATM_AALP_AAL_MODE 0x83 /* AAL mode (UNI 3.0 only) */ #define ATM_AALP_SSCS 0x84 /* SSCS type */ +/* The following constants tag message parser errors. */ + +#define RECOV_IND_IE 1 /* IE problem */ + +/* The following constants tag application-specific errors. */ + +#define RECOV_ASE_UNKNOWN_IE 1 /* unknown IE */ + #endif diff -ur --new-file old/atm/qgen/qgen.h new/atm/qgen/qgen.h --- old/atm/qgen/qgen.h Sat Aug 31 13:41:35 1996 +++ new/atm/qgen/qgen.h Fri Sep 27 20:39:52 1996 @@ -25,6 +25,8 @@ typedef struct { /* --- the following fields are initialized by the parser */ VALUE_TYPE type; + const char *recovery; /* only valid if vt_length; NULL if not used */ + const char *abort_id; /* non-NULL to request application-specific error */ const char *id; /* for value-only and for default tag */ struct _field *block; /* length */ struct _tag *tags; /* case or multi */ @@ -69,6 +71,7 @@ VALUE_LIST *more; /* only for named selectors */ const char *value; FIELD *block; + const char *abort_id; /* non-NULL to request application-specific error */ struct _tag *next; int deflt; /* --- the following fields are initialized in the first phase */ diff -ur --new-file old/atm/qgen/ql.l new/atm/qgen/ql.l --- old/atm/qgen/ql.l Sat Aug 31 13:35:39 1996 +++ new/atm/qgen/ql.l Fri Sep 27 21:37:16 1996 @@ -22,6 +22,7 @@ static int lineno = 1; +static void halt(void) { } static const char *ident(const char *str) { TREE **walk; @@ -49,6 +50,7 @@ length return TOK_LENGTH; multi return TOK_MULTI; recover return TOK_RECOVER; +abort return TOK_ABORT; [_a-zA-Z0-9]+ { yylval.str = ident(yytext); return TOK_ID; } \n?[\t ]* lineno += *yytext && *yytext == '\n'; diff -ur --new-file old/atm/qgen/ql.y new/atm/qgen/ql.y --- old/atm/qgen/ql.y Sat Aug 31 14:51:56 1996 +++ new/atm/qgen/ql.y Fri Sep 27 21:39:09 1996 @@ -31,6 +31,7 @@ static MACRO *macros = NULL; static int repeated = 0; /* current macro contains repeatitions */ static int repeating = 0; /* ancestor is repeated */ +static const char *abort_id; /* indicates abort flag */ static NAME_LIST *get_name_list(const char *name) @@ -101,15 +102,15 @@ }; %token TOK_BREAK TOK_CASE TOK_DEF TOK_DEFAULT TOK_LENGTH TOK_MULTI -%token TOK_RECOVER +%token TOK_RECOVER TOK_ABORT %token TOK_ID TOK_INCLUDE TOK_STRING %type rep_block block fields field field_cont -%type repetition opt_break opt_pos decimal opt_more opt_recover +%type repetition opt_break opt_pos decimal opt_more %type opt_val value %type tags rep_tags %type list -%type opt_id +%type opt_id opt_recover %type opt_name_list %% @@ -160,6 +161,7 @@ if (repeating) yyerror("can't nest repetitions"); repeating = repeated = 1; } + abort_id = NULL; } block { @@ -196,10 +198,17 @@ next = (*walk)->next; free(*walk); *walk = next; + abort_id = NULL; } | '{' fields '}' { $$ = $2; + abort_id = NULL; + } + | TOK_ABORT TOK_ID + { + $$ = NULL; + abort_id = $2; } ; @@ -340,17 +349,19 @@ { $$ = alloc_t(VALUE); $$->type = vt_length; + $$->recovery = $1; $$->block = $3; + $$->abort_id = abort_id; } ; opt_recover: { - $$ = 0; + $$ = NULL; } - | TOK_RECOVER + | TOK_RECOVER TOK_ID { - $$ = 1; + $$ = $2; } ; @@ -383,10 +394,16 @@ $$->more = $4; $$->block = $5; $$->next = NULL; + $$->abort_id = abort_id; } - | TOK_ID opt_id list block tags + | TOK_ID opt_id list block { $$ = alloc_t(TAG); + $$->abort_id = abort_id; + } + tags + { + $$ = $5; $$->deflt = 0; if ($2) { $$->id = $1; @@ -398,7 +415,7 @@ } $$->more = $3; $$->block = $4; - $$->next = $5; + $$->next = $6; } ; @@ -422,9 +439,14 @@ $$->block = $5; $$->next = NULL; } - | TOK_ID opt_id list rep_block rep_tags + | TOK_ID opt_id list rep_block { $$ = alloc_t(TAG); + $$->abort_id = abort_id; + } + rep_tags + { + $$ = $5; $$->deflt = 0; if ($2) { $$->id = $1; @@ -436,7 +458,7 @@ } $$->more = $3; $$->block = $4; - $$->next = $5; + $$->next = $6; } ; diff -ur --new-file old/atm/qgen/qlib.c new/atm/qgen/qlib.c --- old/atm/qgen/qlib.c Wed Sep 4 20:41:01 1996 +++ new/atm/qgen/qlib.c Fri Sep 27 20:17:40 1996 @@ -30,7 +30,7 @@ { va_list ap; - if (!debug) return; + if (!debug && severity > Q_ERROR) return; va_start(ap,msg); vprintf(msg,ap); printf("\n"); @@ -42,6 +42,7 @@ #define LENGTH_STACK 10 +#define LENGTH_R_STACK 5 typedef struct { @@ -49,6 +50,14 @@ unsigned char *start; } LEN_BUF; +typedef struct _rstack { + int *pc; + int sp; + unsigned char *pos; + unsigned char *end; + struct _rstack *next; +} RSTACK; + static int q_test(unsigned char *table,int pos) { @@ -62,6 +71,12 @@ } +static void q_clear(unsigned char *table,int pos) +{ + table[pos >> 3] &= ~(1 << (pos & 7)); +} + + /* slightly ugly */ @@ -180,6 +195,7 @@ memset(dsc->length,0,sizeof(int)*Q_VARLEN_FIELDS); } dsc->error = 0; + dsc->errors = NULL; return 0; } @@ -419,17 +435,69 @@ #endif +static const char *q_err_msg[] = { "???","not enough space (%d left)", + "case failed (value 0x%x)","application-specific error (code %d)" }; + + +/* + * Rather messy ... too bad C doesn't have function-local functions ... + */ + +static void handle_error(Q_DSC *dsc,int size,unsigned char *buf, + unsigned char **stack,RSTACK *r_stack,int **pc,int *sp,int *rp, + unsigned char **pos,unsigned char **end,Q_ERR_TYPE type,int value) +{ + Q_ERR_DSC *error,**last; + + q_report(Q_ERROR,q_err_msg[type],value); + q_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->type = type; + error->pc = *pc-parse; + error->offset = *pos-buf; + error->value = value; + if (*rp) { + (*rp)--; + error->id = r_stack[*rp].pc[0]; + error->start = r_stack[*rp].pos-buf; + *sp = r_stack[*rp].sp; + *pos = r_stack[*rp].end; + error->length = *pos-r_stack[*rp].pos; + error->group = r_stack[*rp].pc[1]; + *pc = parse+r_stack[*rp].pc[2]; + } + else { + error->id = 0; + error->start = 0; + error->length = size; + error->group = 0; + *sp = 0; + *pc = parse+sizeof(parse)/sizeof(*parse)-1; + *pos = buf+size; + } + for (last = &dsc->errors; *last; last = &(*last)->next); + *last = error; + error->next = NULL; +} + + +#define ERROR(type,value) \ + handle_error(dsc,size,buf,stack,r_stack,&pc,&sp,&rp,&pos,&end,type,value) + + static int _q_parse(Q_DSC *dsc,unsigned char *buf,int size) { + RSTACK r_stack[LENGTH_R_STACK]; unsigned char *stack[LENGTH_STACK]; unsigned char *pos,*end; int *pc; - int i,sp; + int i,sp,rp; end = buf+size; pos = buf; pc = parse; - sp = 0; + sp = rp = 0; while (1) { q_report(Q_DEBUG,"%d(%d):",pc-parse,pos-buf); switch (*pc++) { @@ -466,10 +534,8 @@ #endif case OP_COPY: if (pos+*pc > end) { - q_report(Q_ERROR,"not enough space (%d+%d > %d)",pos-buf, - *pc,end-buf); - dsc->error = 1; - return -1; + ERROR(qet_space,end-buf); + continue; } q_report(Q_DEBUG,"copy %d %d %d",pc[1],pos-buf,pc[2]); q_copy(pos,pc[1] & 7,dsc->data+(pc[1] >> 3),pc[2]); @@ -496,16 +562,11 @@ } case OP_BEGIN_LEN: if (pos+*pc > end) { - q_report(Q_ERROR,"not enough space (%d+%d > %d)",pos-buf, - *pc,end-buf); - dsc->error = 1; - return -1; - } - if (sp == LENGTH_STACK) { - q_report(Q_ERROR,"length stack overflow"); - dsc->error = 1; - return -1; + ERROR(qet_space,end-buf); + continue; } + if (sp == LENGTH_STACK) + q_report(Q_FATAL,"length stack overflow"); stack[sp] = end; end = pos+q_get(pos,pc[1] & 7,pc[2])+*pc; if (end > stack[sp]) q_report(Q_FATAL,"length has grown"); @@ -513,19 +574,33 @@ sp++; pc += 3; break; + case OP_BEGIN_REC: + q_report(Q_DEBUG,"begin_rec pc %d sp %d pos %d end %d", + pc-parse,sp,pos-buf,end-buf); + if (rp == LENGTH_R_STACK) + q_report(Q_FATAL,"recovery stack overflow"); + r_stack[rp].pc = pc; + r_stack[rp].sp = sp; + r_stack[rp].pos = pos; + r_stack[rp].end = end; + rp++; + pc += 3; + break; case OP_END_LEN: if (!sp--) q_report(Q_FATAL,"length stack underflow"); end = stack[sp]; break; + case OP_END_REC: + q_report(Q_DEBUG,"end_rec"); + if (!rp--) q_report(Q_FATAL,"recovery stack underflow"); + break; case OP_CASE: { int len,value,group; if (pos+*pc > end) { - q_report(Q_ERROR,"not enough space (%d+%d > %d)", - pos-buf,*pc,end-buf); - dsc->error = 1; - return -1; + ERROR(qet_space,end-buf); + continue; } value = q_get(pos,pc[1] & 7,pc[2]); pos += *pc; @@ -541,8 +616,8 @@ break; } if (!len) { - q_report(Q_ERROR,"case failed (pc %d)",pc-parse); - return -1; + ERROR(qet_case,value); + continue; } } break; @@ -554,8 +629,11 @@ if (pos == end) pc += *pc; pc++; break; + case OP_ABORT: + ERROR(qet_abort,*pc); + continue; case OP_END: - return 0; + return dsc->errors ? -1 : 0; default: q_report(Q_FATAL,"unrecognized opcode %d",pc[-1]); return -1; /* for gcc */ @@ -564,6 +642,35 @@ } +#define GROUP_STACK_SIZE 100 /* make sure it's big enough ... */ + + +static void fixups(Q_DSC *dsc) +{ + int gs[GROUP_STACK_SIZE]; + Q_ERR_DSC *walk; + int gp,i,j; + + for (walk = dsc->errors; walk; walk = walk->next) { + gs[gp = 0] = walk->group; + q_clear(dsc->group_present,walk->group); + for (i = walk->group+1; i < Q_GROUPS; i++) { + while (groups[i].parent != gs[gp]) + if (!gp--) break; + if (gp < 0) break; + gs[++gp] = i; + q_clear(dsc->group_present,i); + } + for (j = 0; j < Q_FIELDS; j++) + if (fields[j].parent == walk->group) break; + while (j < Q_FIELDS && fields[j].parent < i) { + q_clear(dsc->field_present,j); + j++; + } + } +} + + static int q_parse(Q_DSC *dsc,unsigned char *buf,int size) { int error; @@ -577,7 +684,10 @@ putc('\n',stderr); } error = _q_parse(dsc,buf,size); - if (error) return error; + if (error) { + fixups(dsc); + return error; + } if (q_dump) { putc('\n',stderr); for (j = 0; j < 100; j += 20) { @@ -630,6 +740,13 @@ free(dsc->field_present); free(dsc->group_present); if (dsc->length) free(dsc->length); + while (dsc->errors) { + Q_ERR_DSC *next; + + next = dsc->errors->next; + free(dsc->errors); + dsc->errors = next; + } return dsc->error ? -1 : dsc->buffer ? size : 0; } diff -ur --new-file old/atm/qgen/qlib.h new/atm/qgen/qlib.h --- old/atm/qgen/qlib.h Fri Aug 30 21:04:20 1996 +++ new/atm/qgen/qlib.h Fri Sep 27 20:22:23 1996 @@ -34,6 +34,20 @@ #endif +typedef enum { qet_catch_zero,qet_space,qet_case,qet_abort } Q_ERR_TYPE; + +typedef struct _q_err_dsc { + Q_ERR_TYPE type; /* error type code */ + int pc; /* PC when error was discovered */ + int offset; /* offset into message when error was discovered */ + int value; /* additional value (optional) */ + int id; /* user-assigned id */ + int start; /* recovery area */ + int length; + int group; /* group that failed (for fixups) */ + struct _q_err_dsc *next; +} Q_ERR_DSC; + typedef struct { unsigned char *data; unsigned char *required; @@ -43,9 +57,10 @@ void *buffer; int buf_size; int error; + Q_ERR_DSC *errors; } Q_DSC; - + void PREFIX(start)(void); int PREFIX(open)(Q_DSC *dsc,void *buf,int size); int q_create(Q_DSC *dsc,void *buf,int size); diff -ur --new-file old/atm/qgen/third.c new/atm/qgen/third.c --- old/atm/qgen/third.c Sat Aug 31 14:23:15 1996 +++ new/atm/qgen/third.c Fri Sep 27 20:44:35 1996 @@ -92,12 +92,12 @@ } -static void parser(FIELD *start,int level) +static void parser(FIELD *start,int level,int group) { FIELD *walk; TAG *scan; VALUE_LIST *tag; - int count; + int count,patch_here; BREAK *brk,*tmp_brks,*next; for (walk = start; walk; walk = walk->next) { @@ -159,7 +159,9 @@ patch(scan->patch,pc-scan->patch-1); for (tag = scan->more; tag; tag = tag->next) patch(tag->patch,pc-tag->patch-1); - parser(scan->block,level+1); + if (!scan->block && scan->abort_id) + code("%s%s\n","OP_ABORT",scan->abort_id); + parser(scan->block,level+1,scan->group); if (scan->next) { code("%s%s\n","OP_JUMP","?"); scan->patch = pc-1; @@ -176,8 +178,19 @@ case vt_length: code("%s%d%d%d/* %s */\n","OP_BEGIN_LEN",walk->jump, walk->pos,walk->size,walk->id); + if (walk->value->recovery) { + code("%s%s%d%d\n","OP_BEGIN_REC",walk->value->recovery, + group,"?"); + patch_here = pc-1; + } tmp_brks = brks; - parser(walk->value->block,level+1); + if (!walk->value->block && walk->value->abort_id) + code("%s%s\n","OP_ABORT",walk->value->abort_id); + parser(walk->value->block,level+1,group); + if (walk->value->recovery) { + code("%s\n","OP_END_REC"); + patch(patch_here,pc); + } for (brk = brks; brk; brk = next) { next = brk->next; patch(brk->pc,pc-brk->pc-1); @@ -218,7 +231,7 @@ to_dump("static DUMP_FIELD dump_fields[] = {\n"); } begin_code(); - parser(def,0); + parser(def,0,0); parser_size = end_code()+1; to_c(" OP_END\n};\n\n"); if (dump) to_dump("};\n\n"); diff -ur --new-file old/atm/qgen/uni3x new/atm/qgen/uni3x --- old/atm/qgen/uni3x Sat Aug 31 14:49:07 1996 +++ new/atm/qgen/uni3x Fri Sep 27 20:47:03 1996 @@ -18,7 +18,7 @@ name##_cs "q2931_cs" <2@6,more> = defl \ _flag "atm_flag" <1@5,more> = ATM_FLAG_NO \ _action_ind "atm_ai_ie" <3@1> = 0 /* only 2 bits in UNI 3.0 */ \ - _ie_len <16> = recover length + _ie_len <16> = recover RECOV_IND_IE length #define ITU_STD_HDR VAR_STD_HDR(,Q2931_CS_ITU) #define NET_STD_HDR VAR_STD_HDR(,Q2931_CS_NET) @@ -482,7 +482,8 @@ ep_ref: ATM_IE_EPR ie_ep_ref ep_state: ATM_IE_EP_STATE ie_ep_state default 0 { - unknown_ie <-240> # this is used as a flag + VAR_STD_HDR(_,0) + abort RECOV_ASE_UNKNOWN_IE } } } diff -ur --new-file old/atm/saal/Makefile new/atm/saal/Makefile --- old/atm/saal/Makefile Wed Jul 31 14:37:04 1996 +++ new/atm/saal/Makefile Tue Sep 17 15:30:33 1996 @@ -1,5 +1,5 @@ LIBS= -OBJS=saal.o sscf.o sscop.o +OBJS=saal.o sscf.o sscop.o queue.o all: libsaal.a diff -ur --new-file old/atm/saal/queue.c new/atm/saal/queue.c --- old/atm/saal/queue.c Thu Jan 1 01:00:00 1970 +++ new/atm/saal/queue.c Tue Sep 17 15:31:47 1996 @@ -0,0 +1,99 @@ +/* queue.c - Quick and very very dirty buffer and queue handling */ + +/* Written 1995-1996 by Werner Almesberger, EPFL-LRC */ + + +#include +#include + +#include "atmd.h" + +#include "queue.h" + + +BUFFER *buffer_create(int length,int key) +{ + BUFFER *buf; + + buf = alloc_t(BUFFER); + buf->data = alloc(length); + buf->length = length; + buf->key = key; + return buf; +} + + +BUFFER *buffer_clone(BUFFER *b) +{ + BUFFER *buf; + + buf = buffer_create(b->length,b->key); + memcpy(buf->data,b->data,b->length); + return buf; +} + + +void buffer_discard(BUFFER *b) +{ + free(b->data); + free(b); +} + + +void queue_init(QUEUE *q) +{ + q->first = q->last = NULL; +} + + +void queue_put(QUEUE *q,BUFFER *b) +{ + Q_INSERT_AFTER(q->first,b,q->last); + q->last = b; +} + + +void queue_remove(QUEUE *q,BUFFER *b) +{ + if (q->last == b) q->last = b->prev; + Q_REMOVE(q->first,b); +} + + +BUFFER *queue_peek(QUEUE *q) +{ + return q->first; +} + + +BUFFER *queue_get(QUEUE *q) +{ + BUFFER *buf; + + buf = queue_peek(q); + if (buf) queue_remove(q,buf); + return buf; +} + + +BUFFER *queue_lookup(QUEUE *q,int key) +{ + BUFFER *walk; + + for (walk = q->first; walk; walk = walk->next) + if (walk->key == key) break; + return walk; +} + + +void queue_clear(QUEUE *q) +{ + BUFFER *next; + + while (q->first) { + next = q->first->next; + buffer_discard(q->first); + q->first = next; + } + q->last = NULL; +} diff -ur --new-file old/atm/saal/queue.h new/atm/saal/queue.h --- old/atm/saal/queue.h Thu Jan 1 01:00:00 1970 +++ new/atm/saal/queue.h Tue Sep 17 15:31:51 1996 @@ -0,0 +1,33 @@ +/* queue.h - Quick and very very dirty buffer and queue handling */ + +/* Written 1995-1996 by Werner Almesberger, EPFL-LRC */ + + +#ifndef QUEUE_H +#define QUEUE_H + +typedef struct _buffer { + void *data; + int length; /* TX buffer: of the entire PDU; RX buffer: of the data */ + int key; /* SD.N(S) */ + int extra; /* SD.N(PS) */ + struct _buffer *next,*prev; +} BUFFER; + +typedef struct { + BUFFER *first,*last; +} QUEUE; + + +BUFFER *buffer_create(int length,int key); +BUFFER *buffer_clone(BUFFER *b); +void buffer_discard(BUFFER *b); +void queue_init(QUEUE *q); +void queue_put(QUEUE *q,BUFFER *b); +void queue_remove(QUEUE *q,BUFFER *b); +BUFFER *queue_peek(QUEUE *q); +BUFFER *queue_get(QUEUE *q); +BUFFER *queue_lookup(QUEUE *q,int key); +void queue_clear(QUEUE *q); + +#endif diff -ur --new-file old/atm/saal/sscop.c new/atm/saal/sscop.c --- old/atm/saal/sscop.c Fri May 31 15:44:11 1996 +++ new/atm/saal/sscop.c Tue Sep 17 15:50:19 1996 @@ -13,6 +13,7 @@ #include "atmd.h" #include "sscop.h" +#include "queue.h" /* @@ -256,6 +257,13 @@ } +static int sdu_length(BUFFER *buf) +{ + return buf->length-4-SSCOP_PAD(*(unsigned long *) ((char *) buf->data+ + buf->length-4)); +} + + 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) { @@ -931,7 +939,7 @@ BUFFER *buf; if (NORM_RX(s) >= NORM_RX(dsc->vr_mr)) { - if (NORM_RX(dsc->vr_h) >= NORM_RX(dsc->vr_mr)) { + if (NORM_RX(dsc->vr_h) < NORM_RX(dsc->vr_mr)) { send_ustat(dsc,dsc->vr_h,dsc->vr_mr); dsc->vr_h = dsc->vr_mr; } @@ -1749,13 +1757,13 @@ if (buf) { queue_remove(&dsc->tx_buf,buf); if (dsc->ops->retr_ind) - dsc->ops->retr_ind(dsc->user,buf->data,buf->length); + dsc->ops->retr_ind(dsc->user,buf->data,sdu_length(buf)); buffer_discard(buf); } } while ((buf = queue_get(&dsc->tx_q))) { if (dsc->ops->retr_ind) - dsc->ops->retr_ind(dsc->user,buf->data,buf->length); + dsc->ops->retr_ind(dsc->user,buf->data,sdu_length(buf)); buffer_discard(buf); } if (dsc->ops->retr_comp) dsc->ops->retr_comp(dsc->user); diff -ur --new-file old/atm/saal/sscop.h new/atm/saal/sscop.h --- old/atm/saal/sscop.h Tue Oct 24 17:55:57 1995 +++ new/atm/saal/sscop.h Thu Sep 26 18:14:28 1996 @@ -1,12 +1,14 @@ /* sscop.h - SSCOP (Q.2110) user interface */ -/* Written 1995 by Werner Almesberger, EPFL-LRC */ +/* Written 1995,1996 by Werner Almesberger, EPFL-LRC */ #ifndef SSCOP_H #define SSCOP_H #include "atmd.h" + +#include "queue.h" typedef enum { sscop_idle,sscop_outconn,sscop_inconn,sscop_outdisc, diff -ur --new-file old/atm/sigd/q2931.c new/atm/sigd/q2931.c --- old/atm/sigd/q2931.c Wed Sep 4 22:06:08 1996 +++ new/atm/sigd/q2931.c Thu Sep 26 20:17:06 1996 @@ -562,9 +562,29 @@ } +static void abort_call(void) +{ + SOCKET *curr; + unsigned long call_ref; + + diag(COMPONENT,DIAG_ERROR,"can't parse message - aborting the call"); + call_ref = q_fetch(&in_dsc,QF_call_ref)^0x800000; + /* hope that at least the call ref was okay ... */ + for (curr = sockets; curr; curr = curr->next) + if (curr->call_ref == call_ref) { + q2931_call(curr,QMSG_RESTART); + break; + } + send_release_complete(call_ref,ATM_CV_PROTOCOL_ERROR); +} + + void to_q2931(void *msg,int size) { - q_open(&in_dsc,msg,size); + if (q_open(&in_dsc,msg,size) < 0) { + abort_call(); + return; + } process_q2931(msg); if (q_close(&in_dsc) < 0) diag(COMPONENT,DIAG_ERROR,"q_close returned <0 in to_q2931"); .