diff -ur --new-file old/linux/drivers/atm/eni.c new/linux/drivers/atm/eni.c
--- old/linux/drivers/atm/eni.c	Wed Jul 31 19:46:56 1996
+++ new/linux/drivers/atm/eni.c	Wed Jul 31 19:47:25 1996
@@ -526,8 +526,14 @@
 			size = 0;
 		}
 		else {
-			printk(KERN_WARNING DEV_LABEL "(itf %d): discarding "
-			    "PDU with CRC error\n",vcc->dev->number);
+			static unsigned long silence = 0;
+
+			if (jiffies > silence) {
+				printk(KERN_WARNING DEV_LABEL "(itf %d): "
+				    "discarding PDU(s) with CRC error\n",
+				    vcc->dev->number);
+				silence = jiffies+2*HZ;
+			}
 			size = (descr & MID_RED_COUNT)*(ATM_CELL_PAYLOAD >> 2);
 			EVENT("CRC error (descr=0x%08lx,size=%ld)\n",descr,
 			    size);
@@ -665,7 +671,7 @@
 		}
 		ENI_VCC(vcc)->timestamp = xtime;
 		ENI_VCC(vcc)->next = NULL;
-		if (vcc->rxtp.class == ATM_CBR) {
+		if (vcc->qos.rxtp.traffic_class == ATM_CBR) {
 			if (eni_dev->fast)
 				ENI_VCC(eni_dev->last_fast)->next = vcc;
 			else eni_dev->fast = vcc;
@@ -745,8 +751,8 @@
 	eni_dev = ENI_DEV(vcc->dev);
 	eni_vcc = ENI_VCC(vcc);
 	eni_vcc->rx = NULL;
-	if (vcc->rxtp.class == ATM_NONE) return 0;
-	size = vcc->rxtp.max_sdu*3; /* @@@ improve this */
+	if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0;
+	size = vcc->qos.rxtp.max_sdu*3; /* @@@ improve this */
 	eni_vcc->recv = (volatile unsigned long *) eni_alloc_mem(eni_dev,&size);
 	DPRINTK("rx at 0x%lx\n",(unsigned long) eni_vcc->recv);
 	eni_vcc->words = size >> 2;
@@ -1142,30 +1148,32 @@
 	eni_dev = ENI_DEV(vcc->dev);
 	eni_vcc = ENI_VCC(vcc);
 	eni_vcc->tx = NULL;
-	if (vcc->txtp.class == ATM_NONE) return 0;
+	if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;
 	eni_vcc->txing = 0;
-	if (vcc->txtp.class != ATM_UBR)
-		size = vcc->txtp.max_sdu*3; /* @@@ improve */
+	if (vcc->qos.txtp.traffic_class != ATM_UBR)
+		size = vcc->qos.txtp.max_sdu*3; /* @@@ improve */
 	else {
 		if (eni_dev->ubr) {
 			eni_vcc->tx = eni_dev->ubr;
 			return 0;
 		}
 		size = UBR_BUFFER;
-		vcc->txtp.min_pcr = ATM_MAX_PCR;
-		vcc->txtp.max_pcr = 0;
+		vcc->qos.txtp.min_pcr = ATM_MAX_PCR;
+		vcc->qos.txtp.max_pcr = 0;
 	}
 	DPRINTK("get_tx\n");
 	mem = eni_alloc_mem(eni_dev,&size);
 	if (!mem) return -ENOBUFS;
-	if ((tx_ind = alloc_tx(eni_dev,&pcr,vcc->txtp.min_pcr,
-	    vcc->txtp.max_pcr,vcc->txtp.class == ATM_UBR)) < 0) {
+	if ((tx_ind = alloc_tx(eni_dev,&pcr,vcc->qos.txtp.min_pcr,
+	    vcc->qos.txtp.max_pcr,vcc->qos.txtp.traffic_class == ATM_UBR)) < 0)
+	    {
 		eni_free_mem(eni_dev,mem,size);
 		return tx_ind;
 	}
-	if (vcc->txtp.class == ATM_UBR) eni_dev->ubr = &eni_dev->tx[tx_ind];
+	if (vcc->qos.txtp.traffic_class == ATM_UBR)
+		eni_dev->ubr = &eni_dev->tx[tx_ind];
 	else eni_dev->tx_bw -= pcr;
-	vcc->txtp.min_pcr = vcc->txtp.max_pcr = pcr;
+	vcc->qos.txtp.min_pcr = vcc->qos.txtp.max_pcr = pcr;
 	eni_dev->tx[tx_ind].send = (volatile unsigned long *) mem;
 	eni_dev->tx[tx_ind].words = size >> 2;
 	skb_queue_head_init(&eni_dev->tx[tx_ind].backlog);
@@ -1664,15 +1672,16 @@
 	if (*vpi == ATM_VPI_ANY) *vpi = 0;
 	if (*vci == ATM_VCI_ANY) {
 		for (*vci = ATM_NOT_RSV_VCI; *vci < NR_VCI; (*vci)++) {
-			if (vcc->rxtp.class != ATM_NONE &&
+			if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
 			    ENI_DEV(vcc->dev)->rx_map[*vci])
 				continue;
-			if (vcc->txtp.class != ATM_NONE) {
+			if (vcc->qos.txtp.traffic_class != ATM_NONE) {
 				for (walk = vcc->dev->vccs; walk;
 				    walk = walk->next)
 					if ((walk->flags & ATM_VF_ADDR) &&
 					    walk->vci == *vci &&
-					    walk->txtp.class != ATM_NONE)
+					    walk->qos.txtp.traffic_class !=
+					    ATM_NONE)
 						break;
 				if (walk) continue;
 			}
@@ -1681,12 +1690,13 @@
 		return *vci == NR_VCI ? -EADDRINUSE : 0;
 	}
 	if (*vci == ATM_VCI_UNSPEC) return 0;
-	if (vcc->rxtp.class != ATM_NONE && ENI_DEV(vcc->dev)->rx_map[*vci])
+	if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
+	    ENI_DEV(vcc->dev)->rx_map[*vci])
 		return -EADDRINUSE;
-	if (vcc->txtp.class == ATM_NONE) return 0;
+	if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;
 	for (walk = vcc->dev->vccs; walk; walk = walk->next)
 		if ((walk->flags & ATM_VF_ADDR) && walk->vci == *vci &&
-		    walk->txtp.class != ATM_NONE)
+		    walk->qos.txtp.traffic_class != ATM_NONE)
 			return -EADDRINUSE;
 	return 0;
 }
diff -ur --new-file old/linux/drivers/atm/tneta1570.c new/linux/drivers/atm/tneta1570.c
--- old/linux/drivers/atm/tneta1570.c	Wed Jul 31 19:46:56 1996
+++ new/linux/drivers/atm/tneta1570.c	Wed Jul 31 19:47:26 1996
@@ -791,7 +791,7 @@
 
    	tneta1570_vcc->tx_wait = NULL;
 
-        if (vcc->txtp.class == ATM_NONE) return 0;
+        if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;
 
         tneta1570_vcc->seg_ring_mptr=kmalloc(2*TX_SEG_RING_SIZE*4, GFP_KERNEL);
         if(!tneta1570_vcc->seg_ring_mptr) {
diff -ur --new-file old/linux/drivers/atm/zatm.c new/linux/drivers/atm/zatm.c
--- old/linux/drivers/atm/zatm.c	Wed Jul 31 19:46:56 1996
+++ new/linux/drivers/atm/zatm.c	Wed Jul 31 19:47:25 1996
@@ -384,7 +384,7 @@
 	pos = (zatm_dev->mbx_start[mbx] & ~0xffff) | zin(MTA(mbx));
 	while (x = zin(MWA(mbx)), (pos & 0xffff) != x) {
 		unsigned long *here;
-		struct sk_buff *skb,*expect;
+		struct sk_buff *skb;
 		struct atm_vcc *vcc;
 		int cells,size,chan;
 
@@ -436,17 +436,7 @@
 			vcc = zatm_dev->rx_map[chan];
 			if (skb == zatm_dev->last_free[ZATM_VCC(vcc)->pool])
 				zatm_dev->last_free[ZATM_VCC(vcc)->pool] = NULL;
-			expect = skb_dequeue(&zatm_dev->pool[ZATM_VCC(vcc)->
-                            pool]);
-			if (skb != expect) {
-				printk(KERN_CRIT DEV_LABEL "(itf %d): skb "
-				    "mismatch - got 0x%08lx, expected "
-				    "0x%08lx\n",dev->number,
-				    (unsigned long) skb,(unsigned long) expect);
-				size = 0;
-				vcc = NULL;
-				event_dump();
-			}
+			skb_unlink(skb);
 		}
 		else {
 			printk(KERN_ERR DEV_LABEL "(itf %d): RX indication "
@@ -456,8 +446,16 @@
 			event_dump();
 		}
 		if (error) {
-			printk(KERN_WARNING DEV_LABEL "(itf %d): chan %d "
-			    "error %s\n",dev->number,chan,err_txt[error]);
+			static unsigned long silence = 0;
+			static int last_error = 0;
+
+			if (error != last_error || jiffies > silence) {
+				printk(KERN_WARNING DEV_LABEL "(itf %d): "
+				    "chan %d error %s\n",dev->number,chan,
+				    err_txt[error]);
+				last_error = error;
+				silence = jiffies+2*HZ;
+			}
 			size = 0;
 		}
 		if (size && (size > cells*ATM_CELL_PAYLOAD-ATM_AAL5_TRAILER ||
@@ -507,13 +505,14 @@
 	zatm_dev = ZATM_DEV(vcc->dev);
 	zatm_vcc = ZATM_VCC(vcc);
 	zatm_vcc->rx_chan = 0;
-	if (vcc->rxtp.class == ATM_NONE) return 0;
+	if (vcc->qos.rxtp.traffic_class == ATM_NONE) return 0;
 	if (vcc->aal == ATM_AAL5) {
-		if (vcc->rxtp.max_sdu > 65464) vcc->rxtp.max_sdu = 65464;
+		if (vcc->qos.rxtp.max_sdu > 65464)
+			vcc->qos.rxtp.max_sdu = 65464;
 			/* fix this - we may want to receive 64kB SDUs
 			   later */
-		cells = (vcc->rxtp.max_sdu+ATM_AAL5_TRAILER+ATM_CELL_PAYLOAD-1)/
-		    ATM_CELL_PAYLOAD;
+		cells = (vcc->qos.rxtp.max_sdu+ATM_AAL5_TRAILER+
+		    ATM_CELL_PAYLOAD-1)/ATM_CELL_PAYLOAD;
 		zatm_vcc->pool = pool_index(cells*ATM_CELL_PAYLOAD);
 	}
 	else {
@@ -795,8 +794,8 @@
 	for (shaper = 0; !((zatm_dev->free_shapers >> shaper) & 1); shaper++);
 	zatm_dev->free_shapers &= ~1 << shaper;
 	if (ubr) {
-		i = c = 5;
-		m = 1;
+		c = 5;
+		i = m = 1;
 		zatm_dev->ubr_ref_cnt++;
 		zatm_dev->ubr = shaper;
 	}
@@ -822,6 +821,11 @@
 				m = (ATM_OC3_PCR*255+max-1)/max;
 			}
 		}
+		if (i > m) {
+			printk(KERN_CRIT DEV_LABEL "shaper algorithm botched "
+			    "[%d,%d] -> i=%ld,m=%ld\n",min,max,i,m);
+			m = i;
+		}
 		*pcr = i*ATM_OC3_PCR/m;
 		c = 20; /* @@@ should use max_cdv ! */
 		if ((min && *pcr < min) || (max && *pcr > max)) return -EINVAL;
@@ -908,7 +912,7 @@
 	zatm_vcc->tx_chan = 0;
 	zatm_dev->tx_map[chan] = NULL;
 	if (zatm_vcc->shaper != zatm_dev->ubr) {
-		zatm_dev->tx_bw += vcc->txtp.min_pcr;
+		zatm_dev->tx_bw += vcc->qos.txtp.min_pcr;
 		dealloc_shaper(vcc->dev,zatm_vcc->shaper);
 	}
 	if (zatm_vcc->ring) kfree(zatm_vcc->ring);
@@ -927,7 +931,7 @@
 	zatm_dev = ZATM_DEV(vcc->dev);
 	zatm_vcc = ZATM_VCC(vcc);
 	zatm_vcc->tx_chan = 0;
-	if (vcc->txtp.class == ATM_NONE) return 0;
+	if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;
 	save_flags(flags);
 	cli();
 	zwait;
@@ -938,18 +942,18 @@
 	restore_flags(flags);
 	DPRINTK("chan is %d\n",chan);
 	if (!chan) return -EAGAIN;
-	if (vcc->txtp.class == ATM_UBR && zatm_dev->ubr != -1)
+	if (vcc->qos.txtp.traffic_class == ATM_UBR && zatm_dev->ubr != -1)
 		zatm_vcc->shaper = zatm_dev->ubr;
 	else {
-		if (vcc->txtp.class == ATM_UBR)
-			vcc->txtp.max_sdu = ATM_MAX_AAL5_PDU;
+		if (vcc->qos.txtp.traffic_class == ATM_UBR)
+			vcc->qos.txtp.max_sdu = ATM_MAX_AAL5_PDU;
 		if ((zatm_vcc->shaper = alloc_shaper(vcc->dev,&pcr,
-		    vcc->txtp.min_pcr,vcc->txtp.max_pcr,
-		    vcc->txtp.class == ATM_UBR)) < 0) {
+		    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,
+		    vcc->qos.txtp.traffic_class == ATM_UBR)) < 0) {
 			close_tx(vcc);
 			return zatm_vcc->shaper;
 		}
-		vcc->txtp.min_pcr = vcc->txtp.max_pcr = pcr;
+		vcc->qos.txtp.min_pcr = vcc->qos.txtp.max_pcr = pcr;
 	}
 	zatm_vcc->tx_chan = chan;
 	skb_queue_head_init(&zatm_vcc->tx_queue);
@@ -1402,19 +1406,7 @@
 	int error;
 
 	zatm_dev = ZATM_DEV(dev);
-printk(KERN_CRIT "got here!\n");
 	switch (cmd) {
-case ZATM_TUNE:
-{
-	unsigned long old;
-
-	old = zin(GMR);
-printk(KERN_INFO "got 0x%08lx\n",old);
-	zout((old & ~0xf00) | (arg & 0xf00),GMR);
-	return old;
-
-}
-
 		case ZATM_GETPOOLZ:
 			if (!suser()) return -EPERM;
 			/* fall through */
@@ -1529,12 +1521,14 @@
 }
 
 
+#if 0
 static int zatm_sg_send(struct atm_vcc *vcc,unsigned long start,
     unsigned long size)
 {
 	return vcc->aal == ATM_AAL5;
 	   /* @@@ should check size and maybe alignment*/
 }
+#endif
 
 
 static int zatm_send(struct atm_vcc *vcc,struct sk_buff *skb)
@@ -1592,7 +1586,7 @@
 	zatm_getsockopt,
 	zatm_setsockopt,
 	zatm_send,
-	zatm_sg_send,
+	NULL /*zatm_sg_send*/,
 	NULL,			/* no poll */
 	NULL,			/* no send_oam */
 	zatm_phy_put,
diff -ur --new-file old/linux/drivers/atm/zatm.h new/linux/drivers/atm/zatm.h
--- old/linux/drivers/atm/zatm.h	Wed Jul 31 19:46:56 1996
+++ new/linux/drivers/atm/zatm.h	Wed Jul 31 19:47:25 1996
@@ -14,7 +14,7 @@
 						/* get statistics and zero */
 #define ZATM_SETPOOL	_IOW('a',ATMIOC_SARPRV+3,struct atmif_sioc)
 						/* set pool parameters */
-#define ZATM_TUNE _IOW('a',ATMIOC_SARPRV+4,struct atmif_sioc)
+
 
 struct zatm_pool_info {
 	int ref_count;			/* free buffer pool usage counters */
diff -ur --new-file old/linux/include/linux/arequipa.h new/linux/include/linux/arequipa.h
--- old/linux/include/linux/arequipa.h	Wed Jul 31 19:46:58 1996
+++ new/linux/include/linux/arequipa.h	Wed Jul 31 19:47:28 1996
@@ -13,6 +13,8 @@
 #define AREQUIPA_INCOMING	_IO('a',ATMIOC_AREQUIPA+1)
 #define AREQUIPA_EXPECT		_IO('a',ATMIOC_AREQUIPA+2)
 #define AREQUIPA_CLOSE		_IO('a',ATMIOC_AREQUIPA+3)
+#define AREQUIPA_CTRL		_IO('a',ATMIOC_AREQUIPA+4)
+#define AREQUIPA_CLS3RD		_IO('a',ATMIOC_AREQUIPA+5)
 
 
 #ifdef __KERNEL__
@@ -23,6 +25,7 @@
 #include <net/route.h>
 
 
+extern struct atm_vcc *aqd; /* for net/atm/proc.c */
 /* extern struct rtable arequipa_rt; - not needed */
 extern struct device *arequipa_dev;
 
@@ -33,6 +36,9 @@
 int arequipa_expect(struct sock *upper,int on);
 int arequipa_incoming(struct socket *lower);
 int arequipa_close(struct sock *upper);
+
+int arequipad_attach(struct atm_vcc *vcc);
+void arequipa_close_vcc(struct atm_vcc *vcc);
 
 #endif /* __KERNEL__ */
 
diff -ur --new-file old/linux/include/linux/atm.h new/linux/include/linux/atm.h
--- old/linux/include/linux/atm.h	Wed Jul 31 19:46:56 1996
+++ new/linux/include/linux/atm.h	Wed Jul 31 19:47:26 1996
@@ -135,8 +135,9 @@
 
 #define ATM_MAX_PCR	-1		/* maximum available PCR */
 
+#define class traffic_class		/* backward compatibility */
 struct atm_trafprm {
-	unsigned char	class;		/* traffic class (ATM_UBR, ...) */
+	unsigned char	traffic_class;	/* traffic class (ATM_UBR, ...) */
 	int		max_pcr;	/* maximum PCR in cells per second */
 	int		min_pcr;	/* minimum PCR in cells per second */
 	int		max_cdv;	/* maximum CDV in microseconds */
@@ -164,8 +165,6 @@
 		short	vpi;		/* VPI (only 8 bits at UNI) */
 		int	vci;		/* VCI (only 16 bits at UNI) */
 	}		sap_addr;	/* PVC address */
-	struct atm_trafprm sap_txtp;	/* TX traffic parameters */
-	struct atm_trafprm sap_rxtp;	/* RX traffic parameters */
 };
 
 /* SVC addressing */
@@ -188,8 +187,6 @@
         struct atm_blli	*blli;		/* local SAP, low-layer information */
         struct atm_bhli	bhli;		/* local SAP, high-layer information */
     }			sas_addr;	/* SVC address */
-    struct atm_trafprm	sas_txtp;	/* TX traffic parameters */
-    struct atm_trafprm	sas_rxtp;	/* RX traffic parameters */
 };
 
 
diff -ur --new-file old/linux/include/linux/atmdev.h new/linux/include/linux/atmdev.h
--- old/linux/include/linux/atmdev.h	Wed Jul 31 19:46:56 1996
+++ new/linux/include/linux/atmdev.h	Wed Jul 31 19:47:26 1996
@@ -10,6 +10,7 @@
 #include <linux/config.h>
 #include <linux/uio.h>
 #include <linux/atmioc.h>
+#include <asm/atomic.h>
 
 
 #define MAX_ATM_ITF	10	/* for now, should be lowered */
@@ -111,12 +112,12 @@
 				   socket layer */
 #define ATM_VF_RELEASED 16	/* demon has indicated/requested release,
 				   controlled by SVC socket layer */
-#define ATM_VF_HASQOS	32	/* QOS parameters have been set using the
-				   new API */
+#define ATM_VF_HASQOS	32	/* QOS parameters have been set */
 #define ATM_VF_LISTEN	64	/* socket is used for listening */
 #define ATM_VF_META	128	/* SVC socket isn't used for normal data
 				   traffic and doesn't depend on signaling
 				   to be available */
+#define ATM_VF_AQREL	256	/* Arequipa socket is being released */
 
 struct atm_vcc {
 	unsigned short	flags;		/* VCC flags (ATM_VF_*) */
@@ -128,10 +129,9 @@
 	unsigned long	aal_options;	/* AAL layer options */
 	unsigned long	atm_options;	/* ATM layer options */
 	struct atm_dev	*dev;		/* device back pointer */
-	struct atm_trafprm txtp,rxtp;	/* traffic parameters */
-	struct atm_qos	qos;		/* QOS - only valid if ATM_VF_HASQOS */
+	struct atm_qos	qos;		/* QOS */
 	unsigned long	tx_quota,rx_quota; /* buffer quotas */
-	unsigned long	tx_inuse,rx_inuse; /* buffer space in use */
+	atomic_t	tx_inuse,rx_inuse; /* buffer space in use */
 	void (*push)(struct atm_vcc *vcc,struct sk_buff *skb);
 	void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */
 	struct sk_buff *(*peek)(struct atm_vcc *vcc,unsigned long pdu_size,
diff -ur --new-file old/linux/include/linux/atmsvc.h new/linux/include/linux/atmsvc.h
--- old/linux/include/linux/atmsvc.h	Wed Jul 31 19:46:56 1996
+++ new/linux/include/linux/atmsvc.h	Wed Jul 31 19:47:26 1996
@@ -13,23 +13,23 @@
 #define ATMSIGD_CTRL _IO('a',ATMIOC_SPECIAL)
 				/* become ATM signaling demon control socket */
 
-enum atmsvc_msg_type { as_catch_null,as_bind,as_establish,as_listen,as_okay,
-  as_indicate,as_close,as_itf_notify };
+enum atmsvc_msg_type { as_catch_null,as_bind,as_connect,as_accept,as_listen,
+  as_okay,as_error,as_indicate,as_close,as_itf_notify };
 
 struct atmsvc_msg {
 	enum atmsvc_msg_type type;
 	unsigned long vcc;
 	unsigned long listen_vcc;	/* indicate */
-	int reply;			/* for okay and close:
-					 *   < 0: error before active
-					 *        (sigd has discarded ctx)
-					 *   ==0: success
-				         *   > 0: error when active (still need
-					 *        to close)
-					 */
+	int reply;			/* for okay and close:		   */
+					/*   < 0: error before active	   */
+					/*        (sigd has discarded ctx) */
+					/*   ==0: success		   */
+				        /*   > 0: error when active (still */
+					/*        need to close)	   */
 	unsigned char aal;		/* AAL */
 	struct sockaddr_atmpvc pvc;	/* indicate, okay (connect) */
 	struct sockaddr_atmsvc local;	/* local SVC address */
+	struct atm_qos qos;		/* QOS parameters */
 	struct sockaddr_atmsvc svc;	/* MUST BE BEFORE "blli", SVC address */
 	struct atm_blli blli[1];	/* MUST BE LAST */
 };
@@ -41,18 +41,17 @@
  *                                         addr *xtp addr sap *xtp addr
  * bind	     K->D  X      -        -    -   -    -    X    X   -    -
  * - okay    D->K  X      -        -    -   -    -    X    X   -    -
- * establish K->D  X      -        -    X   -    -    X    X   X    X
+ * connect   K->D  X      -        -    X   -    -    X    X   X    X
  * - okay    D->K  X      -        -    -   X    X    -    -   -    X
  * listen    K->D  X      -        -    X   -    -    X    X   X    -
  * - okay    D->K  X      -        -    -   -    -    -    -   -    -
- * indicate  D->K  -      X        -    -   X    2    X    X   X    -
- * accept1   K->D  X      X        -    -   -    -    -    -   -    -
+ * indicate  D->K  -      X        -    -   X    1    X    X   X    -
+ * accept    K->D  X      X        -    -   -    -    -    -   -    -
  * - okay    D->K  X      -        -    -   -    -    -    -   -    X
  * close     K->D  X      -        -    -   -    -    -    -   -    -
  * close     D->K  X      -        X    -   -    -    -    -   -    -
  *
- *  1  (establish)
- *  2  same value as in svc.*xtp
+ *  1  same value as in svc.*xtp
  *
  * Note: we may have to get rid of the PVC part in indicate messages later,
  *       so it's a good idea not to depend on it too heavily.
diff -ur --new-file old/linux/include/linux/mm.h new/linux/include/linux/mm.h
--- old/linux/include/linux/mm.h	Wed Jul 31 19:46:57 1996
+++ new/linux/include/linux/mm.h	Sun Jun  9 11:23:32 1996
@@ -142,7 +142,6 @@
 #define PG_decr_after		 5
 #define PG_swap_unlock_after	 6
 #define PG_DMA			 7
-#define PG_single_copy		 8 /* page is locked for single copy */
 #define PG_reserved		31
 
 /* Make it prettier to test the above... */
@@ -155,7 +154,6 @@
 #define PageDecrAfter(page)	(test_bit(PG_decr_after, &(page)->flags))
 #define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags))
 #define PageDMA(page)		(test_bit(PG_DMA, &(page)->flags))
-#define PageSingleCopy(page)	(test_bit(PG_single_copy, &(page)->flags))
 #define PageReserved(page)	(test_bit(PG_reserved, &(page)->flags))
 
 /*
diff -ur --new-file old/linux/include/net/sock.h new/linux/include/net/sock.h
--- old/linux/include/net/sock.h	Wed Jul 31 19:46:58 1996
+++ new/linux/include/net/sock.h	Wed Jul 31 19:47:28 1996
@@ -251,8 +251,8 @@
 	unsigned char		max_ack_backlog;
 	unsigned char		priority;
 	unsigned char		debug;
-	unsigned short		rcvbuf;
-	unsigned short		sndbuf;
+	unsigned long		rcvbuf;
+	unsigned long		sndbuf;
 	unsigned short		type;
 	unsigned char		localroute;	/* Route locally only */
 #ifdef CONFIG_AX25
diff -ur --new-file old/linux/net/atm/arequipa.c new/linux/net/atm/arequipa.c
--- old/linux/net/atm/arequipa.c	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/arequipa.c	Wed Jul 31 19:47:26 1996
@@ -22,6 +22,7 @@
 #include <asm/system.h> /* cli and such */
 
 #include "protocols.h"
+#include "tunable.h"
 #include "signaling.h"  /* for indirect closing, see below */
 #include "common.h"
 #include "ipcommon.h"
@@ -36,6 +37,7 @@
 
 struct device *arequipa_dev = NULL;
     /* must use a different null value if skb->dev can ever be NULL */
+struct atm_vcc *aqd = NULL;
 
 struct rtable arequipa_rt = {
 	NULL,		/* rt_next */
@@ -58,11 +60,34 @@
 /*
  * Closing is tricky. Since we may be in an interrupt when executing
  * arequipa_close, we can't just go and call close_fp. So what we do it instead
- * is to ask signaling nicely to close the SVC. Signaling does its job and then
- * comes back to close us (in arequipa_callback). Now we're in a process
- * context and can sleep, etc.
+ * is to ask arequipad nicely to close the VC. arequipad issues an
+ * AREQUIPA_CLS3RD ioctl to close us (via arequipa_close_vcc). Now we're in a
+ * process context and can sleep, etc. Ain't life sweet ?
  */
 
+
+static void aqd_enq(struct atm_vcc *vcc)
+{
+	struct sk_buff *skb;
+
+	if (!aqd) {
+		printk(KERN_CRIT "aqd_enq: no Arequipa demon\n");
+		return;
+	}
+	skb = alloc_skb(sizeof(vcc),GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "adq_enq: out of memory\n");
+		return;
+	}
+	skb->free = 1;
+	skb->len = sizeof(vcc);
+	*(struct atm_vcc **) skb->data = vcc;
+	atomic_add(skb->truesize+ATM_PDU_OVHD,&aqd->rx_inuse);
+	skb_queue_tail(&aqd->recvq,skb);
+	wake_up(&aqd->sleep);
+}
+
+
 int arequipa_close(struct sock *upper)
 {
 	struct socket *lower;
@@ -74,20 +99,32 @@
 	cli();
 	upper->arequipa = NULL;
 	ATM_SD(lower)->upper = NULL;
+	if (!(ATM_SD(lower)->flags & ATM_VF_AQREL)) aqd_enq(ATM_SD(lower));
+	ATM_SD(lower)->flags |= ATM_VF_AQREL;
 	restore_flags(flags);
-	sigd_enq_atomic(ATM_SD(lower),as_close,NULL,NULL,NULL);
-	ATM_SD(lower)->flags &= ~ATM_VF_REGIS;
 	return 0;
 }
 
 
+void arequipa_close_vcc(struct atm_vcc *vcc)
+{
+	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);
+}
+
 
 static void arequipa_callback(struct atm_vcc *vcc)
 {
+	unsigned long flags;
+
 	DPRINTK("arequipa_callback\n");
 	svc_callback(vcc);
 	if (!(vcc->flags & ATM_VF_RELEASED)) return;
 	vcc->callback = svc_callback; /* paranoia ... */
+	save_flags(flags);
+	cli();
 	if (vcc->upper) {
 		if (!vcc->upper->arequipa)
 			printk("arequipa_callback: upper pretends not to "
@@ -95,17 +132,22 @@
 		ip_rt_put(vcc->upper->ip_route_cache);
 		vcc->upper->ip_route_cache = NULL;
 		vcc->upper->arequipa = NULL;
-		vcc->callback = svc_callback;
 	}
-	close_fp(vcc->sock->file);
+	if (vcc->flags & ATM_VF_AQREL) {
+		restore_flags(flags);
+		return;
+	}
+	vcc->flags |= ATM_VF_AQREL;
+	restore_flags(flags);
+	arequipa_close_vcc(vcc);
 	return;
 }
 
 
 static int check_aq_vcc(struct socket *lower)
 {
-	if (lower->ops->family != PF_ATMSVC) return -EPROTOTYPE;
-	    /* no PVCs, because we need to be closed by a 3rd party */
+	if (lower->ops->family != PF_ATMSVC && lower->ops->family != PF_ATMPVC)
+		return -EPROTOTYPE;
 	if (lower->state != SS_CONNECTED) return -ENOTCONN;
 	if (ATM_SD(lower)->aal != ATM_AAL5) return -EPROTONOSUPPORT;
 	return 0;
@@ -170,6 +212,10 @@
 int arequipa_expect(struct sock *upper,int on)
 {
 	DPRINTK("arequipa_expect %d\n",on);
+	if (!aqd) {
+		printk(KERN_ERR "arequipa_expect: no Arequipa demon\n");
+		return -EUNATCH;
+	}
 	if (on) {
 		if (upper->aq_route) return 0;
 		upper->aq_route = kmalloc(sizeof(struct rtable),GFP_KERNEL);
@@ -187,6 +233,10 @@
 {
 	int error;
 
+	if (!aqd) {
+		printk(KERN_ERR "arequipa_preset: no Arequipa demon\n");
+		return -EUNATCH;
+	}
 	error = arequipa_expect(upper,1);
 	if (error) return error;
 	error = arequipa_attach(lower,upper);
@@ -255,4 +305,63 @@
 	arequipa_dev->init = arequipa_init;
 	arequipa_init(arequipa_dev);
 	return 0;
+}
+
+
+static void aqd_close(struct atm_vcc *vcc)
+{
+        struct sk_buff *skb;
+
+        DPRINTK("aqd_close\n");
+        aqd = NULL; /* assumed to be atomic */
+	barrier();
+        if (skb_peek(&vcc->recvq))
+                printk(KERN_CRIT "aqd_close: closing with requests "
+		    "pending\n");
+        while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb,FREE_READ);
+}
+
+
+static struct atmdev_ops aqd_dev_ops = {
+	NULL,		/* no open */
+	aqd_close,	/* close */
+	NULL,		/* no ioctl */
+	NULL,		/* no getsockopt */
+	NULL,		/* no setsockopt */
+	NULL,		/* no send */
+	NULL,		/* no sg_send */
+	NULL,		/* no poll */
+	NULL,		/* no phy_put */
+	NULL,		/* no phy_get */
+	NULL		/* no feedback */
+};
+
+
+static struct atm_dev aqd_dev = {
+	&aqd_dev_ops,
+	NULL,		/* no PHY */
+	"aqd",		/* type */
+	999,		/* dummy device number */
+	NULL,NULL,	/* pretend not to have any VCCs */
+	NULL,NULL,	/* no data */
+	0,		/* no flags */
+	NULL,		/* no local address */
+	{ 0 }		/* no ESI, no statistics */
+};
+
+
+int arequipad_attach(struct atm_vcc *vcc)
+{
+	if (aqd) return -EADDRINUSE;
+	aqd = vcc;
+	vcc->flags |= ATM_VF_READY | ATM_VF_META;
+	    /* allow replies and avoid getting closed if signaling dies */
+	vcc->dev = &aqd_dev;
+	vcc->aal = ATM_AAL5; /* lie */
+	vcc->push = NULL;
+	vcc->peek = NULL; /* crash */
+	vcc->pop = NULL; /* crash */
+	vcc->push_oam = NULL; /* crash */
+        return 0;
+
 }
diff -ur --new-file old/linux/net/atm/atmarp.c new/linux/net/atm/atmarp.c
--- old/linux/net/atm/atmarp.c	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/atmarp.c	Wed Jul 31 19:47:26 1996
@@ -32,6 +32,7 @@
 
 
 #include "common.h"
+#include "tunable.h"
 #include "protocols.h" /* for atm_push_raw */
 #include "ipcommon.h"
 #include "atmarp.h"
@@ -116,6 +117,7 @@
 	ctrl->arg = arg;
 	if (data) memcpy(ctrl->data,data,length);
 	reply = WAITING;
+	atomic_add(skb->truesize+ATM_PDU_OVHD,&atmarpd->rx_inuse);
 	skb_queue_tail(&atmarpd->recvq,skb);
 	wake_up(&atmarpd->sleep);
 	if (!need_reply) return 0;
@@ -313,6 +315,8 @@
 		memcpy((void *) skb->data,llc_oui,sizeof(llc_oui));
 		((unsigned short *) skb->data)[3] = htons(ETH_P_IP);
 	}
+	DPRINTK("CX(A) %d += %d\n",entry->vcc->tx_inuse,skb->truesize);
+	atomic_add(skb->truesize,&entry->vcc->tx_inuse);
 	skb->atm.iovcnt = 0;
 	AE(entry->vcc)->last_use = jiffies;
 	entry->vcc->dev->ops->send(entry->vcc,skb);
@@ -559,7 +563,7 @@
 	NULL,		/* no ioctl */
 	NULL,		/* no getsockopt */
 	NULL,		/* no setsockopt */
-	atmarpd_send,	/* no send */
+	atmarpd_send,	/* send */
 	NULL,		/* no sg_send */
 	NULL,		/* no poll */
 	NULL,		/* no phy_put */
diff -ur --new-file old/linux/net/atm/clip.c new/linux/net/atm/clip.c
--- old/linux/net/atm/clip.c	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/clip.c	Wed Jul 31 19:47:26 1996
@@ -91,6 +91,7 @@
 int atm_init_clip(struct atm_vcc *vcc)
 {
 	struct device *dev;
+	int number;
 
 	DPRINTK("atm_init_clip\n");
 	if (!suser()) return -EPERM;
@@ -101,13 +102,14 @@
 	vcc->push_oam = NULL;
 	vcc->proto_data = dev = kmalloc(sizeof(struct device)+
 	    sizeof(struct clip_priv),GFP_KERNEL);
-	if (!vcc->proto_data) return -ENOMEM;
+	if (!dev) return -ENOMEM;
 	memset(dev,0,sizeof(struct device)+sizeof(struct clip_priv));
 	dev->name = CLIP(dev)->name;
-	sprintf(dev->name,"atm%d",pvc_num++);
+	number = pvc_num++;
+	sprintf(dev->name,"atm%d",number);
 	dev->init = clip_init;
 	CLIP(dev)->vcc = vcc;
 	if (register_netdev(dev)) return -EIO;
 	DPRINTK("registered %s,0x%lx\n",dev->name,(unsigned long) vcc);
-	return 0;
+	return number;
 }
diff -ur --new-file old/linux/net/atm/common.c new/linux/net/atm/common.c
--- old/linux/net/atm/common.c	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/common.c	Wed Jul 31 19:47:26 1996
@@ -48,7 +48,13 @@
 
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
-	return alloc_skb(size,GFP_KERNEL);
+	struct sk_buff *skb;
+
+	if (size+vcc->tx_inuse+ATM_PDU_OVHD > vcc->tx_quota) return NULL;
+	while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule();
+	DPRINTK("AlTx %d += %d\n",vcc->tx_inuse,skb->truesize);
+	atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
+	return skb;
 }
 
 
@@ -71,8 +77,8 @@
 	vcc->callback = NULL;
 	memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
 	memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc));
-	vcc->tx_quota = ATM_RXBQ_DEF*1024;
-	vcc->rx_quota = ATM_TXBQ_DEF*1024;
+	vcc->tx_quota = ATM_TXBQ_DEF;
+	vcc->rx_quota = ATM_RXBQ_DEF;
 	vcc->tx_inuse = vcc->rx_inuse = 0;
 	switch (protocol) {
 		/*
@@ -146,23 +152,27 @@
 
 static int adjust_tp(struct atm_trafprm *tp,unsigned char aal)
 {
+	int max_sdu;
+
 	if (!tp->class) return 0;
 	if (tp->class != ATM_UBR && !tp->min_pcr && !tp->max_pcr)
 		return -EINVAL;
-	if (!tp->max_sdu)
-		switch (aal) {
-			case ATM_AAL0:
-				tp->max_sdu = ATM_CELL_SIZE-1;
-				break;
-			case ATM_AAL34:
-				tp->max_sdu = ATM_MAX_AAL34_PDU;
-				break;
-			default:
-				printk(KERN_WARNING "ATM: AAL problems ... "
-				    "(%d)\n",aal);
-			case ATM_AAL5:
-				tp->max_sdu = ATM_MAX_AAL5_PDU;
-		}
+	switch (aal) {
+		case ATM_AAL0:
+			max_sdu = ATM_CELL_SIZE-1;
+			break;
+		case ATM_AAL34:
+			max_sdu = ATM_MAX_AAL34_PDU;
+			break;
+		default:
+			printk(KERN_WARNING "ATM: AAL problems ... "
+			    "(%d)\n",aal);
+			/* fall through */
+		case ATM_AAL5:
+			max_sdu = ATM_MAX_AAL5_PDU;
+	}
+	if (!tp->max_sdu) tp->max_sdu = max_sdu;
+	else if (tp->max_sdu > max_sdu) return -EINVAL;
 	if (!tp->max_cdv) tp->max_cdv = ATM_MAX_CDV;
 	return 0;
 }
@@ -174,9 +184,10 @@
 
 	for (walk = vcc->dev->vccs; walk; walk = walk->next)
 		if ((walk->flags & ATM_VF_ADDR) && walk->vpi == vpi &&
-		    walk->vci == vci && ((walk->txtp.class != ATM_NONE &&
-		    vcc->txtp.class != ATM_NONE) || (walk->rxtp.class !=
-		    ATM_NONE && vcc->rxtp.class != ATM_NONE)))
+		    walk->vci == vci && ((walk->qos.txtp.traffic_class !=
+		    ATM_NONE && vcc->qos.txtp.traffic_class != ATM_NONE) ||
+		    (walk->qos.rxtp.traffic_class != ATM_NONE &&
+		    vcc->qos.rxtp.traffic_class != ATM_NONE)))
 			return -EADDRINUSE;
 		/* allow VCCs with same VPI/VCI iff they don't collide on
 		   TX/RX (but we may refuse such sharing for other reasons,
@@ -251,15 +262,15 @@
 			    "(%d)\n",vcc->dev->type,vcc->dev->number,vcc->aal);
 			return -EINVAL;
 	}
-	error = adjust_tp(&vcc->txtp,vcc->aal);
-	if (!error) error = adjust_tp(&vcc->rxtp,vcc->aal);
+	error = adjust_tp(&vcc->qos.txtp,vcc->aal);
+	if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->aal);
 	if (error) return error;
 	vcc->dev = (struct atm_dev *) dev;
 	DPRINTK("VCC %d.%d, AAL %d\n",vpi,vci,vcc->aal);
-	DPRINTK("  TX: %d, PCR %d..%d, SDU %d\n",vcc->txtp.class,
-	    vcc->txtp.min_pcr,vcc->txtp.max_pcr,vcc->txtp.max_sdu);
-	DPRINTK("  RX: %d, PCR %d..%d, SDU %d\n",vcc->rxtp.class,
-	    vcc->rxtp.min_pcr,vcc->rxtp.max_pcr,vcc->rxtp.max_sdu);
+	DPRINTK("  TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class,
+	    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
+	DPRINTK("  RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.class,
+	    vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
 	if (dev->ops->open) {
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
@@ -290,10 +301,12 @@
 		vcc->flags &= ~ATM_VF_PARTIAL;
 	else if (vcc->flags & ATM_VF_PARTIAL) return -EINVAL;
 	printk("atm_connect (TX: cl %d,bw %d-%d,sdu %d; RX: cl %d,bw %d-%d,"
-	    "sdu %d)\n",vcc->txtp.class,vcc->txtp.min_pcr,vcc->txtp.max_pcr,
-	    vcc->txtp.max_sdu,vcc->rxtp.class,vcc->rxtp.min_pcr,
-	    vcc->rxtp.max_pcr,vcc->rxtp.max_sdu);
-	if (vcc->txtp.class == ATM_ANYCLASS || vcc->rxtp.class == ATM_ANYCLASS)
+	    "sdu %d)\n",vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr,
+	    vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu,
+	    vcc->qos.rxtp.traffic_class,vcc->qos.rxtp.min_pcr,
+	    vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
+	if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
+	    vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
 		return -EINVAL;
 	if (itf != ATM_ITF_ANY) error = atm_do_connect(vcc,itf,vpi,vci);
 	else {
@@ -360,6 +373,8 @@
 	if (vcc->dev->ops->feedback)
 		vcc->dev->ops->feedback(vcc,skb,(unsigned long) skb->data,
 		    (unsigned long) buff,eff_len);
+	DPRINTK("RcvM %d -= %d\n",vcc->rx_inuse,skb->truesize);
+	atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->rx_inuse);
 #ifdef CONFIG_MMU_HACKS
 	mmucp_tofs((unsigned long) buff,eff_len,skb,(unsigned long) skb->data);
 #else
@@ -428,6 +443,8 @@
 		}
 		else {
 			DPRINTK("res is %d\n",res);
+			DPRINTK("Asnd %d += %d\n",vcc->tx_inuse,skb->truesize);
+			atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
 			skb->atm.iovcnt = res;
 			skb_device_lock(skb);
 			vcc->dev->ops->send(vcc,skb);
@@ -437,8 +454,7 @@
 	}
 #endif
 	eff = (size+3) & ~3; /* align to word boundary */
-	while (size+vcc->tx_inuse+ATM_PDU_OVHD > vcc->tx_quota ||
-	    !(skb = vcc->alloc_tx(vcc,eff))) {
+	while (!(skb = vcc->alloc_tx(vcc,eff))) {
 		if (nonblock) return -EAGAIN;
 		interruptible_sleep_on(&vcc->sleep);
 		if (current->signal & ~current->blocked)
@@ -491,8 +507,8 @@
 			return 1;
 		case SEL_OUT:
 			if (sock->state == SS_CONNECTING) break;
-			if (vcc->txtp.class == ATM_NONE) return 1;
-			if (vcc->txtp.max_sdu+vcc->tx_inuse+ATM_PDU_OVHD >
+			if (vcc->qos.txtp.traffic_class == ATM_NONE) return 1;
+			if (vcc->qos.txtp.max_sdu+vcc->tx_inuse+ATM_PDU_OVHD >
 			  vcc->tx_quota) break;
 			return 1;
 		case SEL_EX:
@@ -627,6 +643,15 @@
 			}
 		case AREQUIPA_INCOMING:
 			return arequipa_incoming(sock);
+		case AREQUIPA_CTRL:
+			if (!suser()) return -EPERM;
+			error = arequipad_attach(ATM_SD(sock));
+			if (!error) sock->state = SS_CONNECTED;
+			return error;
+		case AREQUIPA_CLS3RD:
+			if (!suser()) return -EPERM;
+			arequipa_close_vcc((struct atm_vcc *) arg);
+			return 0;
 #endif
 #ifdef CONFIG_ATM_LANE
                 case ATMLEC_CTRL:
@@ -766,15 +791,17 @@
 				if (optlen != sizeof(value)) return -EINVAL;
 				value = get_fs_long(optval);
 				if (!value) value = ATM_TXBQ_DEF;
+				if (value < ATM_TXBQ_MIN) value = ATM_TXBQ_MIN;
 				if (value > ATM_TXBQ_MAX) value = ATM_TXBQ_MAX;
-				vcc->tx_quota = value*1024;
+				vcc->tx_quota = value;
 				return 0;
 			case SO_RCVBUF:
 				if (optlen != sizeof(value)) return -EINVAL;
 				value = get_fs_long(optval);
 				if (!value) value = ATM_RXBQ_DEF;
+				if (value < ATM_RXBQ_MIN) value = ATM_RXBQ_MIN;
 				if (value > ATM_RXBQ_MAX) value = ATM_RXBQ_MAX;
-				vcc->rx_quota = value*1024;
+				vcc->rx_quota = value;
 				return 0;
 			default:
 				return -EINVAL;
@@ -783,9 +810,10 @@
 	if (level == SOL_ATM) {
 		switch (optname) {
 			case SO_ATMQOS:
+				if (sock->state != SS_UNCONNECTED)
+					return -EBADFD;
 				if (optlen != sizeof(struct atm_qos))
 					return -EINVAL;
-				if (vcc->flags & ATM_VF_HASQOS) return -EINVAL;
 				memcpy_fromfs(&vcc->qos,optval,optlen);
 				vcc->flags |= ATM_VF_HASQOS;
 				return 0;
diff -ur --new-file old/linux/net/atm/ipcommon.c new/linux/net/atm/ipcommon.c
--- old/linux/net/atm/ipcommon.c	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/ipcommon.c	Wed Jul 31 19:47:26 1996
@@ -133,6 +133,13 @@
 }
 
 
+static int clip_open(struct device *dev)
+{
+	DPRINTK("clip_open called\n");
+	return 0;
+}
+
+
 static int clip_stop(struct device *dev)
 {
 	DPRINTK("DOWN! (%s,0x%lx)\n",dev->name,(unsigned long) CLIP(dev)->vcc);
@@ -155,6 +162,7 @@
 	dev->sg_xmit = NULL;
 #endif
 #endif
+	dev->open = clip_open;
 	dev->stop = clip_stop;
 	ether_setup(dev);
 	dev->tbusy = 0; /* @@@ check */
diff -ur --new-file old/linux/net/atm/ipcommon.h new/linux/net/atm/ipcommon.h
--- old/linux/net/atm/ipcommon.h	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/ipcommon.h	Wed Jul 31 19:47:26 1996
@@ -50,6 +50,7 @@
 		memcpy(skb->data,llc_oui,sizeof(llc_oui));
 		((unsigned short *) skb->data)[3] = htons(ETH_P_IP); /* hack */
 	}
+	atomic_add(skb->truesize,&vcc->tx_inuse);
 	skb->atm.iovcnt = 0;
 	vcc->dev->ops->send(vcc,skb);
 }
diff -ur --new-file old/linux/net/atm/lec.c new/linux/net/atm/lec.c
--- old/linux/net/atm/lec.c	Wed Jul 31 19:46:58 1996
+++ new/linux/net/atm/lec.c	Wed Jul 31 19:47:27 1996
@@ -168,6 +168,7 @@
                         /* Minimum ethernet-frame size */
                         if (skb->len <62)
                                 skb->len = 62;
+			atomic_add(skb->truesize,&send_vcc->tx_inuse);
                         skb->atm.iovcnt = 0;
                         send_vcc->dev->ops->send(send_vcc, skb);
                         if (priv)
diff -ur --new-file old/linux/net/atm/mmuio.c new/linux/net/atm/mmuio.c
--- old/linux/net/atm/mmuio.c	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/mmuio.c	Wed Jul 31 19:47:26 1996
@@ -4,11 +4,14 @@
 
 
 #include <linux/config.h>
-#include <linux/mmuio.h>
 
 
 #ifdef CONFIG_MMU_HACKS
 
+#include <linux/mmuio.h>
+#include <asm/atomic.h>
+
+
 #define invalidate flush_tlb_all /* @@@ improve this */
 
 
@@ -345,7 +348,6 @@
 {
 	struct vm_area_struct *vma;
 	unsigned long end,last,from,page;
-	unsigned long flags;
 	pgd_t *pgd;
 	pmd_t *pmd;
 	pte_t *pte;
@@ -386,26 +388,13 @@
 			return -EINVAL;
 		}
 		map = mem_map+MAP_NR(page);
-		if (map->reserved) {
+		if (PageReserved(map)) {
 			printk(KERN_ERR "lock_user: reserved\n");
 			event_dump();
 			return -EINVAL;
 		}
-		if (!map->locked && PageSingleCopy(map))
-			printk(KERN_CRIT "strange, !l && u\n");
-		save_flags(flags);
-		cli();
-		while (map->locked /* && SC = 0 or SC = max */) {
-			EVENT("Waiting for page ...\n",0,0,0);
-			wait_on_page(map);
-		}
-		if (!map->locked) {
-			map->count++;
-			map->locked = 1;
-			*pte = pte_wrprotect(*pte);
-		}
-		set_bit(PG_single_copy,&map->flags);
-		restore_flags(flags);
+		atomic_inc(&map->count);
+		*pte = pte_wrprotect(*pte);
 		if (!last) {
 			from = page+(start & (PAGE_SIZE-1));
 			start &= ~(PAGE_SIZE-1);
@@ -457,15 +446,7 @@
 			mem_map_t *map;
 
 			map = mem_map+MAP_NR(walk);
-			if (!clear_bit(PG_single_copy,&map->flags))
-				printk(KERN_CRIT "unlock_user: returning "
-				    "unlocked page\n");
-			/* -- if last lock is gone */
-			EVENT("returning page 0x%08lx\n",walk,0,0);
-			map->locked = 0;
-			wake_up(&map->wait);
 			free_page(walk);
-			/* -- endif */
 		}
 		iov++;
 	}
diff -ur --new-file old/linux/net/atm/proc.c new/linux/net/atm/proc.c
--- old/linux/net/atm/proc.c	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/proc.c	Wed Jul 31 19:47:26 1996
@@ -17,6 +17,7 @@
 #include <linux/atmclip.h>
 #include <linux/atmarp.h>
 #include <linux/if_arp.h>
+#include <linux/arequipa.h> /* to get aqd */
 #include <asm/param.h> /* for HZ */
 
 #include "static.h" /* ugly */
@@ -174,8 +175,9 @@
 	off = sprintf(buf,"%3d %3d %5d %-3s %7d %-5s %7d %-6s",
 	    vcc->dev->number,vcc->vpi,vcc->vci,
 	    vcc->aal >= sizeof(aal_name)/sizeof(aal_name[0]) ? "err" :
-	    aal_name[vcc->aal],vcc->rxtp.min_pcr,class_name[vcc->rxtp.class],
-	    vcc->txtp.min_pcr,class_name[vcc->txtp.class]);
+	    aal_name[vcc->aal],vcc->qos.rxtp.min_pcr,
+	    class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr,
+	    class_name[vcc->qos.txtp.traffic_class]);
 #ifdef CONFIG_ATM_CLIP
 	if (vcc->push == atm_push_clip) {
 		struct device *dev;
@@ -215,6 +217,9 @@
 	here += sprintf(here,"%-10s ",vcc == sigd ? "Signaling" :
 #ifdef CONFIG_ATM_ATMARP
 	    vcc == atmarpd ? "ATMARPctrl" :
+#endif
+#ifdef CONFIG_AREQUIPA
+	    vcc == aqd ? "Arequipa" :
 #endif
 	    vcc_state(vcc));
 	here += sprintf(here,"%s%s",vcc->remote.sas_addr.pub,
diff -ur --new-file old/linux/net/atm/pvc.c new/linux/net/atm/pvc.c
--- old/linux/net/atm/pvc.c	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/pvc.c	Wed Jul 31 19:47:26 1996
@@ -41,24 +41,16 @@
 {
 	struct sockaddr_atmpvc *addr;
 	struct atm_vcc *vcc;
-	/*int error;*/
 
 	if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) return -EINVAL;
 	addr = (struct sockaddr_atmpvc *) sockaddr;
 	if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT;
 	vcc = ATM_SD(sock);
+	if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
 	if (vcc->flags & ATM_VF_PARTIAL) {
 		if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi;
 		if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci;
 	}
-	else if (vcc->flags & ATM_VF_HASQOS) {
-			vcc->txtp = vcc->qos.txtp;
-			vcc->rxtp = vcc->qos.rxtp;
-		}
-		else {
-			vcc->txtp = addr->sap_txtp;
-			vcc->rxtp = addr->sap_rxtp;
-		}
 	return atm_connect(sock,addr->sap_addr.itf,addr->sap_addr.vpi,
 	    addr->sap_addr.vci);
 }
@@ -100,8 +92,6 @@
 	addr->sap_addr.itf = vcc->dev->number;
 	addr->sap_addr.vpi = vcc->vpi;
 	addr->sap_addr.vci = vcc->vci;
-	memcpy(&addr->sap_txtp,&vcc->txtp,sizeof(struct atm_trafprm));
-	memcpy(&addr->sap_rxtp,&vcc->rxtp,sizeof(struct atm_trafprm));
 	return 0;
 }
 
diff -ur --new-file old/linux/net/atm/raw.c new/linux/net/atm/raw.c
--- old/linux/net/atm/raw.c	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/raw.c	Wed Jul 31 19:47:26 1996
@@ -12,6 +12,7 @@
 #include <linux/mmuio.h>
 #include <linux/uio.h>
 
+#include "common.h"
 #include "protocols.h"
 #include "tunable.h"		/* tunable parameters */
 
@@ -30,6 +31,8 @@
 void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb)
 {
 	if (skb) {
+		DPRINTK("APushR %d += %d\n",vcc->rx_inuse,skb->truesize);
+		atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->rx_inuse);
 		skb_queue_tail(&vcc->recvq,skb);
 		wake_up(&vcc->sleep);
 	}
@@ -65,16 +68,22 @@
 {
 	struct sk_buff *skb;
 
-	if (pdu_size+vcc->rx_inuse+ATM_PDU_OVHD <= vcc->rx_quota) {
-		skb = alloc_skb(((pdu_size+3) & ~3)+PAGE_SIZE-1,GFP_ATOMIC);
-		if (skb) {
-			skb->data = (unsigned char *)
-			    (((unsigned long) skb->data+PAGE_SIZE-1) &
-			    ~(PAGE_SIZE-1));
+	if (pdu_size+vcc->rx_inuse+ATM_PDU_OVHD <= vcc->rx_quota)
+		if (pdu_size < PAGE_SIZE) {
+			skb = alloc_skb((pdu_size+3) & ~3,GFP_ATOMIC);
+			if (skb) return skb;
+		}
+		else {
+			skb = alloc_skb(((pdu_size+3) & ~3)+PAGE_SIZE-1,
+			    GFP_ATOMIC);
+			if (skb) {
+				skb->data = (unsigned char *)
+				    (((unsigned long) skb->data+PAGE_SIZE-1) &
+				    ~(PAGE_SIZE-1));
 DPRINTK("PEEK: data at 0x%lx\n",(unsigned long) skb->data);
-			return skb;
+				return skb;
+			}
 		}
-	}
 	vcc->stats->rx_drop++;
 	return NULL;
 }
@@ -86,6 +95,8 @@
 	if (skb->atm.iovcnt)
 		unlock_user(skb->atm.iovcnt,(struct iovec *) skb->data);
 #endif
+	DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->tx_inuse,skb->truesize);
+	atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse);
 	dev_kfree_skb(skb,FREE_WRITE);
 #if 0 /* experimental */
 if (vcc->dev->sending != 1) printk("sending == %d !!!\n",vcc->dev->sending);
diff -ur --new-file old/linux/net/atm/signaling.c new/linux/net/atm/signaling.c
--- old/linux/net/atm/signaling.c	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/signaling.c	Wed Jul 31 19:47:26 1996
@@ -13,6 +13,7 @@
 #include <linux/atmsvc.h>
 #include <linux/atmdev.h>
 
+#include "tunable.h"
 #include "static.h"
 #include "signaling.h"
 
@@ -40,7 +41,6 @@
 	msg = (struct atmsvc_msg *) skb->data;
 	DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type,msg->vcc);
 	vcc = (struct atm_vcc *) msg->vcc;
-	if (!vcc) vcc = (struct atm_vcc *) msg->listen_vcc;
 	switch (msg->type) {
 		case as_okay:
 			vcc->reply = msg->reply;
@@ -56,10 +56,14 @@
 			vcc->itf = msg->pvc.sap_addr.itf;
 			vcc->vpi = msg->pvc.sap_addr.vpi;
 			vcc->vci = msg->pvc.sap_addr.vci;
-			vcc->txtp = msg->pvc.sap_txtp;
-			vcc->rxtp = msg->pvc.sap_rxtp;
+			if (vcc->vpi || vcc->vci) vcc->qos = msg->qos;
+			break;
+		case as_error:
+			vcc->flags &= ~(ATM_VF_REGIS | ATM_VF_READY);
+			vcc->reply = msg->reply;
 			break;
 		case as_indicate:
+			vcc = (struct atm_vcc *) msg->listen_vcc;
 			DPRINTK("as_indicate!!!\n");
 			if (!vcc->backlog_quota) {
 				sigd_enq(0,as_close,(struct atm_vcc *)
@@ -75,15 +79,9 @@
 			}
 			return 0;
 		case as_close:
-			if (msg->reply < 0) {
-				vcc->flags &= ~ATM_VF_REGIS;
-				vcc->reply = msg->reply;
-			}
-			else {
-				vcc->flags |= ATM_VF_RELEASED;
-				vcc->reply = -msg->reply;
-			}
+			vcc->flags |= ATM_VF_RELEASED;
 			vcc->flags &= ~ATM_VF_READY;
+			vcc->reply = msg->reply;
 			break;
 		default:
 			printk(KERN_ALERT "sigd_send: bad message type %d\n",
@@ -96,9 +94,9 @@
 }
 
 
-static void _sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
+void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
     const struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
-    const struct sockaddr_atmsvc *svc,int atomic)
+    const struct sockaddr_atmsvc *svc)
 {
 	struct sk_buff *skb;
 	struct atmsvc_msg *msg;
@@ -113,11 +111,7 @@
 	if (svc)
 		for (walk = svc->sas_addr.blli; walk; walk = walk->next)
 			size += sizeof(struct atm_blli);
-	if (!atomic) while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule();
-	else if (!(skb = alloc_skb(size,GFP_ATOMIC))) {
-			printk(KERN_ALERT "sigd_enq: no memory for message\n");
-			return;
-		}
+	while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule();
 	skb->free = 1;
 	skb->len = size;
 	msg = (struct atmsvc_msg *) skb->data;
@@ -125,6 +119,7 @@
 	msg->vcc = (unsigned long) vcc;
 	msg->listen_vcc = (unsigned long) listen_vcc;
 	msg->aal = vcc ? vcc->aal : 0;
+	msg->qos = vcc->qos;
 	if (!svc) msg->svc.sas_family = 0;
 	else {
 		msg->svc = *svc;
@@ -153,25 +148,10 @@
 		return;
 #endif
 	}
+	atomic_add(skb->truesize+ATM_PDU_OVHD,&sigd->rx_inuse);
 	skb_queue_tail(&sigd->recvq,skb);
 	wake_up(&sigd->sleep);
 	if (vcc) vcc->flags |= ATM_VF_REGIS;
-}
-
-
-void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
-    const struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
-    const struct sockaddr_atmsvc *svc)
-{
-	_sigd_enq(vcc,type,listen_vcc,pvc,svc,0);
-}
-
-
-void sigd_enq_atomic(struct atm_vcc *vcc,enum atmsvc_msg_type type,
-    const struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
-    const struct sockaddr_atmsvc *svc)
-{
-	_sigd_enq(vcc,type,listen_vcc,pvc,svc,1);
 }
 
 
diff -ur --new-file old/linux/net/atm/signaling.h new/linux/net/atm/signaling.h
--- old/linux/net/atm/signaling.h	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/signaling.h	Wed Jul 31 19:47:26 1996
@@ -20,9 +20,6 @@
 void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
     const struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
     const struct sockaddr_atmsvc *svc);
-void sigd_enq_atomic(struct atm_vcc *vcc,enum atmsvc_msg_type type,
-    const struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
-    const struct sockaddr_atmsvc *svc);
 int sigd_attach(struct atm_vcc *vcc);
 
 #endif
diff -ur --new-file old/linux/net/atm/svc.c new/linux/net/atm/svc.c
--- old/linux/net/atm/svc.c	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/svc.c	Wed Jul 31 19:47:26 1996
@@ -152,10 +152,7 @@
 	vcc = ATM_SD(sock);
 	vcc->flags &= ~ATM_VF_BOUND; /* failing rebind will kill old binding */
 	/* @@@ check memory (de)allocation on rebind */
-	if (vcc->flags & ATM_VF_HASQOS) {
-		addr->sas_txtp = vcc->qos.txtp;
-		addr->sas_rxtp = vcc->qos.rxtp;
-	}
+	if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
 	error = copy_svc_addr(&vcc->local,addr);
 	if (error) return error;
 	vcc->reply = WAITING;
@@ -188,18 +185,16 @@
 		if (sock->state != SS_UNCONNECTED) return -EINVAL;
 		addr = (struct sockaddr_atmsvc *) sockaddr;
 		if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT;
-		if (vcc->flags & ATM_VF_HASQOS) {
-			addr->sas_txtp = vcc->qos.txtp;
-			addr->sas_rxtp = vcc->qos.rxtp;
-		}
-		if (addr->sas_txtp.class == ATM_ANYCLASS ||
-		    addr->sas_rxtp.class == ATM_ANYCLASS) return -EINVAL;
-		if (!addr->sas_txtp.class && !addr->sas_rxtp.class)
+		if (!(vcc->flags & ATM_VF_HASQOS)) return -EBADFD;
+		if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
+		    vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
 			return -EINVAL;
+		if (!vcc->qos.txtp.traffic_class &&
+		    !vcc->qos.rxtp.traffic_class) return -EINVAL;
 		error = copy_svc_addr(&vcc->remote,addr);
 		if (error) return error;
 		vcc->reply = WAITING;
-		sigd_enq(vcc,as_establish,NULL,NULL,&vcc->remote);
+		sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote);
 		if (flags & O_NONBLOCK) {
 			sock->state = SS_CONNECTING;
 			return -EINPROGRESS;
@@ -240,8 +235,8 @@
  *
  * #ifndef CONFIG_SINGLE_SIGITF
  */
-	vcc->txtp.max_pcr = SELECT_TOP_PCR(vcc->txtp);
-	vcc->txtp.min_pcr = 0;
+	vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp);
+	vcc->qos.txtp.min_pcr = 0;
 /*
  * #endif
  */
@@ -290,7 +285,7 @@
 		   error */
 		/* wait should be short, so we ignore the non-blocking flag */
 		new_vcc->reply = WAITING;
-		sigd_enq(new_vcc,as_establish,old_vcc,NULL,NULL);
+		sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
 		while (new_vcc->reply == WAITING && sigd)
 			sleep_on(&new_vcc->sleep);
 		if (!sigd) return -EUNATCH;
@@ -300,8 +295,7 @@
 	}
 	if (!sigd) return -EUNATCH;
 	msg = (struct atmsvc_msg *) skb->data;
-	new_vcc->txtp = msg->pvc.sap_txtp;
-	new_vcc->rxtp = msg->pvc.sap_rxtp;
+	new_vcc->qos = msg->qos;
 	new_vcc->remote = msg->svc;
 	/* copy BLLI @@@ */
 	new_vcc->remote.sas_addr.blli = NULL;
@@ -324,7 +318,7 @@
 {
 	struct sockaddr_atmsvc *addr;
 
-	/* this will be fun ... we have: txtp/rxtp, public and private
+	/* this will be fun ... we have: public and private
 	   address, bhli and possibly a lot of bllis. Now address buffers
 	   are static ... argl */
 	/* The solution: use pointers to link bllis */
@@ -339,8 +333,6 @@
 	memcpy(addr,peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local,
 	    sizeof(struct sockaddr_atmsvc));
 	addr->sas_addr.blli = NULL; /* @@@ no - copy it */
-	memcpy(&addr->sas_txtp,&ATM_SD(sock)->txtp,sizeof(struct atm_trafprm));
-	memcpy(&addr->sas_rxtp,&ATM_SD(sock)->rxtp,sizeof(struct atm_trafprm));
 	return 0;
 }
 
diff -ur --new-file old/linux/net/atm/tunable.h new/linux/net/atm/tunable.h
--- old/linux/net/atm/tunable.h	Wed Jul 31 19:46:57 1996
+++ new/linux/net/atm/tunable.h	Wed Jul 31 19:47:26 1996
@@ -1,6 +1,6 @@
 /* net/atm/tunable.h - Tunable parameters of ATM support */
 
-/* Written 1995 by Werner Almesberger, EPFL LRC */
+/* Written 1995,1996 by Werner Almesberger, EPFL LRC */
 
 
 #ifndef NET_ATM_TUNABLE_H
@@ -13,10 +13,12 @@
 				   drivers, in microseconds */
 #endif
 
-#define ATM_RXBQ_DEF	64	/* default RX buffer quota, in kB */
-#define ATM_TXBQ_DEF	64	/* default TX buffer quota, in kB */
-#define ATM_RXBQ_MAX	1024	/* RX buffer quota limit, in kB */
-#define ATM_TXBQ_MAX	1024	/* TX buffer quota limit, in kB */
+#define ATM_RXBQ_DEF	(  64*1024)  /* default RX buffer quota, in bytes */
+#define ATM_TXBQ_DEF	(  64*1024)  /* default TX buffer quota, in bytes */
+#define ATM_RXBQ_MIN	(   1*1024)  /* RX buffer minimum, in bytes */
+#define ATM_TXBQ_MIN	(   1*1024)  /* TX buffer minimum, in bytes */
+#define ATM_RXBQ_MAX	(1024*1024)  /* RX buffer quota limit, in bytes */
+#define ATM_TXBQ_MAX	(1024*1024)  /* TX buffer quota limit, in bytes */
 
 #define ATM_PDU_OVHD	0	/* number of bytes to charge against buffer
 				   quota per PDU */