diff -ur --new-file old/linux/Documentation/Configure.help new/linux/Documentation/Configure.help
--- old/linux/Documentation/Configure.help	Fri Sep 27 22:32:55 1996
+++ new/linux/Documentation/Configure.help	Fri Sep 27 22:33:18 1996
@@ -1237,10 +1237,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
@@ -1262,6 +1263,15 @@
   using printks, but still has some impact on performance. Note that
   extended debugging may create certain race conditions itself. Enable
   this ONLY if you suspect problems with the driver.
+
+Enable usec resolution timestamps
+CONFIG_ATM_ZATM_EXACT_TS
+  The uPD98401 SAR chip supports a high-resolution timer (approx. 30 MHz)
+  that is used for very accurate reception timestamps. Because that timer
+  overflows after 140 seconds, and also to avoid timer drift, time
+  measurements need to be periodically synchronized with the normal
+  system time. Enabling this feature will add some general overhead for
+  timer synchronization and also per-packet overhead for time conversion.
 
 Rolfs TI TNETA1570
 CONFIG_ATM_TNETA1570
diff -ur --new-file old/linux/drivers/atm/Config.in new/linux/drivers/atm/Config.in
--- old/linux/drivers/atm/Config.in	Fri Sep 27 22:32:55 1996
+++ new/linux/drivers/atm/Config.in	Fri Sep 27 22:33:18 1996
@@ -13,6 +13,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
diff -ur --new-file old/linux/drivers/atm/eni.c new/linux/drivers/atm/eni.c
--- old/linux/drivers/atm/eni.c	Fri Sep 27 22:32:55 1996
+++ new/linux/drivers/atm/eni.c	Fri Sep 27 22:33:18 1996
@@ -1712,13 +1712,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)
diff -ur --new-file old/linux/drivers/atm/suni.c new/linux/drivers/atm/suni.c
--- old/linux/drivers/atm/suni.c	Fri Sep 27 22:32:55 1996
+++ new/linux/drivers/atm/suni.c	Fri Sep 27 22:33:19 1996
@@ -64,14 +64,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);
@@ -82,11 +82,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) {
diff -ur --new-file old/linux/drivers/atm/zatm.c new/linux/drivers/atm/zatm.c
--- old/linux/drivers/atm/zatm.c	Fri Sep 27 22:32:55 1996
+++ new/linux/drivers/atm/zatm.c	Fri Sep 27 22:33:19 1996
@@ -115,9 +115,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 */
@@ -326,6 +326,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 ------------------------------------*/
 
 
@@ -416,7 +560,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],
@@ -579,7 +727,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) {
@@ -587,14 +735,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;
@@ -1246,18 +1398,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);
 }
 
@@ -1475,6 +1635,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);
diff -ur --new-file old/linux/drivers/atm/zatm.h new/linux/drivers/atm/zatm.h
--- old/linux/drivers/atm/zatm.h	Fri Sep 27 22:32:55 1996
+++ new/linux/drivers/atm/zatm.h	Fri Sep 27 22:33:19 1996
@@ -6,6 +6,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 <linux/atmioc.h>
 
 #define ZATM_GETPOOL	_IOW('a',ATMIOC_SARPRV+1,struct atmif_sioc)
@@ -14,7 +19,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 */
@@ -29,12 +36,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__
@@ -72,6 +86,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 */
@@ -110,6 +143,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 */
diff -ur --new-file old/linux/include/linux/arequipa.h new/linux/include/linux/arequipa.h
--- old/linux/include/linux/arequipa.h	Fri Sep 27 22:32:56 1996
+++ new/linux/include/linux/arequipa.h	Fri Sep 27 22:33:20 1996
@@ -8,6 +8,15 @@
 
 #include <linux/atmioc.h>
 
+/*
+ * 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)
@@ -30,7 +39,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);
diff -ur --new-file old/linux/include/linux/atmdev.h new/linux/include/linux/atmdev.h
--- old/linux/include/linux/atmdev.h	Fri Sep 27 22:32:55 1996
+++ new/linux/include/linux/atmdev.h	Fri Sep 27 22:33:19 1996
@@ -118,6 +118,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_*) */
@@ -163,6 +164,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
 };
 
diff -ur --new-file old/linux/include/linux/atmlec.h new/linux/include/linux/atmlec.h
--- old/linux/include/linux/atmlec.h	Fri Sep 27 22:32:56 1996
+++ new/linux/include/linux/atmlec.h	Fri Sep 27 22:33:20 1996
@@ -17,13 +17,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 {
@@ -52,6 +57,7 @@
 };
 
 struct atmlec_ioc {
+        int dev_num;
         unsigned char atm_addr[ATM_ESA_LEN];
         unsigned char receive;    /* 1= receive vcc, 0 = send_vcc */
 };
diff -ur --new-file old/linux/include/linux/skbuff.h new/linux/include/linux/skbuff.h
--- old/linux/include/linux/skbuff.h	Fri Sep 27 22:32:55 1996
+++ new/linux/include/linux/skbuff.h	Fri Sep 27 22:33:19 1996
@@ -118,7 +118,12 @@
 		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
 
diff -ur --new-file old/linux/net/atm/arequipa.c new/linux/net/atm/arequipa.c
--- old/linux/net/atm/arequipa.c	Fri Sep 27 22:32:56 1996
+++ new/linux/net/atm/arequipa.c	Fri Sep 27 22:33:19 1996
@@ -57,6 +57,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
@@ -97,6 +119,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));
@@ -108,10 +131,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);
 }
 
 
@@ -125,6 +151,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 "
@@ -159,6 +186,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);
 }
 
@@ -176,29 +204,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;
@@ -209,6 +241,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);
@@ -239,7 +289,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;
 }
diff -ur --new-file old/linux/net/atm/atmarp.c new/linux/net/atm/atmarp.c
--- old/linux/net/atm/atmarp.c	Fri Sep 27 22:32:56 1996
+++ new/linux/net/atm/atmarp.c	Fri Sep 27 22:33:19 1996
@@ -260,6 +260,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;
 }
 
@@ -309,9 +310,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);
diff -ur --new-file old/linux/net/atm/common.c new/linux/net/atm/common.c
--- old/linux/net/atm/common.c	Fri Sep 27 22:32:55 1996
+++ new/linux/net/atm/common.c	Fri Sep 27 22:33:19 1996
@@ -121,8 +121,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;
@@ -590,6 +595,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;
@@ -657,12 +665,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);
@@ -816,6 +824,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:
diff -ur --new-file old/linux/net/atm/lec.c new/linux/net/atm/lec.c
--- old/linux/net/atm/lec.c	Fri Sep 27 22:32:56 1996
+++ new/linux/net/atm/lec.c	Fri Sep 27 22:33:20 1996
@@ -28,9 +28,6 @@
 /*
 #define DPRINTK printk
 */
-
-struct atm_vcc *lecd = NULL;
-
 #define DUMP_PACKETS 0 /* 0 = None,
                         * 1 = 30 first bytes
                         * 2 = Whole packet
@@ -42,27 +39,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;
-
-/* Have we register_netdev() yet? */
-unsigned char registered = 0;
+/* will be lec0, lec1, lec2 etc. */
+static char myname[] = "lecx";
 
-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)
@@ -81,8 +63,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;
 }
@@ -100,10 +81,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) {
@@ -141,7 +121,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;i<skb->len && i <99;i++) {
@@ -158,29 +138,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);
@@ -198,8 +174,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? */
@@ -334,60 +309,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;
         }
@@ -399,21 +380,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 = {
@@ -443,13 +427,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);
@@ -464,9 +448,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;
 }
 
@@ -474,7 +458,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));
@@ -493,7 +477,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;
 }
 
@@ -506,21 +490,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;i<skb->len && i <99;i++) {
                 sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]);
@@ -536,32 +523,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)
@@ -570,8 +558,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++;
         }
 }
 
@@ -582,31 +569,74 @@
 
         /* 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;
-        }
-	
-        lec_arp_init();
-	if (!registered) {
-		registered = 1;
-		if ((result =register_netdev(&dev_lec)) != 0)    
-			return result;
-	}
-        lecd = vcc;
+        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;
+        }
+        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;
+        /* 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;
 }
diff -ur --new-file old/linux/net/atm/lec.h new/linux/net/atm/lec.h
--- old/linux/net/atm/lec.h	Fri Sep 27 22:32:56 1996
+++ new/linux/net/atm/lec.h	Fri Sep 27 22:33:20 1996
@@ -11,6 +11,7 @@
 
 #include <linux/atmdev.h>
 #include <linux/if_ether.h>
+#include <linux/atmlec.h>
 
 #define LEC_HEADER_LEN 16
 
@@ -43,11 +44,64 @@
  *
  */
 
-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_
 
diff -ur --new-file old/linux/net/atm/lec_arpc.c new/linux/net/atm/lec_arpc.c
--- old/linux/net/atm/lec_arpc.c	Fri Sep 27 22:32:56 1996
+++ new/linux/net/atm/lec_arpc.c	Fri Sep 27 22:33:20 1996
@@ -17,64 +17,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
@@ -83,39 +30,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;i<LEC_ARP_TABLE_SIZE;i++) {
-                lec_arp_tables[i] = NULL;
-        }
-        lec_arp_timer.expires = jiffies+LEC_ARP_REFRESH_INTERVAL;
-        lec_freeze = 0;
-        add_timer(&lec_arp_timer);
-}
-
-void
-lec_arp_destroy(void)
-{
-        del_timer(&lec_arp_timer);  
-        lec_freeze = 1;
-        lec_clear_all();
+                priv->lec_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
@@ -139,7 +80,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;
@@ -156,14 +98,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;
@@ -218,8 +160,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
@@ -244,14 +185,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;i<LEC_ARP_TABLE_SIZE;i++) {
                 rulla = lec_arp_tables[i];
                 offset = 0;
@@ -286,6 +233,37 @@
                 }
                 printk("%s",buf);
         }
+        rulla = lec_no_forward;
+        if (rulla)
+                printk("No forward\n");  
+        while(rulla) {
+                offset=0;
+                offset += sprintf(buf+offset,"Mac:");
+                for(j=0;j<ETH_ALEN;j++) {
+                        offset+=sprintf(buf+offset,"%2.2x ",
+                                        rulla->mac_addr[j]&0xff);
+                }
+                offset +=sprintf(buf+offset,"Atm:");
+                for(j=0;j<ATM_ESA_LEN;j++) {
+                        offset+=sprintf(buf+offset,"%2.2x ",
+                                        rulla->atm_addr[j]&0xff);
+                }      
+                offset+=sprintf(buf+offset,
+                                "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
+                                rulla->vcc?rulla->vcc->vpi:0, 
+                                rulla->vcc?rulla->vcc->vci:0, 
+                                rulla->recv_vcc?rulla->recv_vcc->vpi:0,
+                                rulla->recv_vcc?rulla->recv_vcc->vci:0,
+                                rulla->last_used, 
+                                rulla->timestamp, rulla->no_tries);
+                offset+=sprintf(buf+offset,
+                                "Flags:%x, Packets_flooded:%x, Status: %s ",
+                                rulla->flags, rulla->packets_flooded, 
+                                get_status_string(rulla->status));
+                offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
+                rulla = rulla->next;
+                printk("%s",buf);
+        }
         rulla = lec_arp_empty_ones;
         if (rulla)
                 printk("Empty ones\n");  
@@ -317,15 +295,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;i<LEC_ARP_TABLE_SIZE;i++) {
+                for(entry =priv->lec_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;
@@ -333,24 +362,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;
 
@@ -362,8 +390,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;
 }
 
@@ -378,17 +409,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);
         }
 }
 
@@ -401,27 +432,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)
@@ -448,26 +482,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;i<LEC_ARP_TABLE_SIZE;i++) {
                         for(entry = lec_arp_tables[i];entry != NULL;) {
                                 if ((entry->flags) & 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);
@@ -475,9 +514,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 {
@@ -486,14 +524,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;
@@ -502,79 +540,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;i<LEC_ARP_TABLE_SIZE;i++) {
-                for(entry =lec_arp_tables[i];entry != NULL; entry=next) {
-                        next = entry->next;
-                        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;i<LEC_ARP_TABLE_SIZE;i++) {
-                for(entry=lec_arp_tables[i];entry != NULL; entry=next) {
-                        next = entry->next;
-                        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);
 }
 
 /*
@@ -582,109 +551,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_flooded<priv->maximum_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;
+                return priv->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;
-        }
-        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;i<LEC_ARP_TABLE_SIZE;i++) {
-                for(entry=lec_arp_tables[i];entry != NULL; entry=next) {
+                for(entry=priv->lec_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;
 }
 
@@ -692,9 +634,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;
@@ -702,12 +643,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))
@@ -722,41 +663,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;i<LEC_ARP_TABLE_SIZE;i++) {
-                for(tmp=lec_arp_tables[i];tmp;tmp=tmp->next) {
+                for(tmp=priv->lec_arp_tables[i];tmp;tmp=tmp->next) {
                         if (entry != tmp &&
                             !memcmp(tmp->atm_addr, atm_addr,
                                     ATM_ESA_LEN)) { 
@@ -781,39 +724,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
@@ -829,18 +772,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",
@@ -855,7 +798,7 @@
                         ioc_data->atm_addr[16],ioc_data->atm_addr[17],
                 ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
         for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
-                for (entry = lec_arp_tables[i];entry!=NULL;entry=entry->next) {
+                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");
@@ -870,14 +813,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);
                                         }
@@ -897,44 +841,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;i<LEC_ARP_TABLE_SIZE;i++) {
-                for (entry=lec_arp_tables[i];entry!=NULL;entry=entry->next) {
+                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;
                         }
                 }
@@ -949,18 +894,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;
@@ -970,124 +910,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;i<LEC_ARP_TABLE_SIZE;i++) {
-                for(entry = lec_arp_tables[i];entry!=NULL; entry=next) {
+                for(entry = priv->lec_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;
@@ -1098,7 +1030,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);
@@ -1106,11 +1038,11 @@
         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);  
 }
 
diff -ur --new-file old/linux/net/atm/lec_arpc.h new/linux/net/atm/lec_arpc.h
--- old/linux/net/atm/lec_arpc.h	Fri Sep 27 22:32:56 1996
+++ new/linux/net/atm/lec_arpc.h	Fri Sep 27 22:33:20 1996
@@ -40,6 +40,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 */
@@ -75,30 +76,27 @@
 #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);
+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(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);
+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
diff -ur --new-file old/linux/net/atm/proc.c new/linux/net/atm/proc.c
--- old/linux/net/atm/proc.c	Fri Sep 27 22:32:56 1996
+++ new/linux/net/atm/proc.c	Fri Sep 27 22:33:19 1996
@@ -26,10 +26,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
@@ -60,7 +59,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
@@ -264,6 +263,7 @@
 
 
 #ifdef CONFIG_ATM_LANE
+
 static char*
 lec_arp_get_status_string(unsigned char status)
 {
@@ -301,8 +301,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);
@@ -310,6 +311,7 @@
 
         sprintf(buf+offset,"\n");
 }
+
 #endif
 
 
@@ -371,36 +373,50 @@
 			break;
 #endif
 #ifdef CONFIG_ATM_LANE
-               case PROC_ATM_LEC:
-                 {
-                          struct lec_arp_table *entry;
-                          int i, count;
-                          
-                          count = *pos;
-                          for(i=0;i<LEC_ARP_TABLE_SIZE;i++)
-                                  for(entry=lec_arp_tables[i];entry;
-                                      entry=entry->next) {
-                                          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;d<MAX_LEC_ITF;d++) {
+                               if (dev_lec[d] &&
+                                   (priv = (struct lec_priv *)
+                                    dev_lec[d]->priv)) {
+                                       for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
+                                               entry = priv->lec_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;
diff -ur --new-file old/linux/net/atm/pvc.c new/linux/net/atm/pvc.c
--- old/linux/net/atm/pvc.c	Fri Sep 27 22:32:56 1996
+++ new/linux/net/atm/pvc.c	Fri Sep 27 22:33:19 1996
@@ -84,7 +84,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);
diff -ur --new-file old/linux/net/atm/signaling.c new/linux/net/atm/signaling.c
--- old/linux/net/atm/signaling.c	Fri Sep 27 22:32:56 1996
+++ new/linux/net/atm/signaling.c	Fri Sep 27 22:33:19 1996
@@ -120,7 +120,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;
diff -ur --new-file old/linux/net/atm/svc.c new/linux/net/atm/svc.c
--- old/linux/net/atm/svc.c	Fri Sep 27 22:32:56 1996
+++ new/linux/net/atm/svc.c	Fri Sep 27 22:33:19 1996
@@ -280,8 +280,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;
@@ -346,11 +345,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;
 }
 
diff -ur --new-file old/linux/net/ipv4/tcp_input.c new/linux/net/ipv4/tcp_input.c
--- old/linux/net/ipv4/tcp_input.c	Fri Sep 27 22:32:56 1996
+++ new/linux/net/ipv4/tcp_input.c	Fri Sep 27 22:33:20 1996
@@ -440,7 +440,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);
@@ -1812,7 +1812,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/linux/net/ipv4/udp.c new/linux/net/ipv4/udp.c
--- old/linux/net/ipv4/udp.c	Fri Sep 27 22:32:56 1996
+++ new/linux/net/ipv4/udp.c	Fri Sep 27 22:33:19 1996
@@ -663,7 +663,8 @@
 #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;