diff -ur --new-file old/linux/include/linux/atmsvc.h new/linux/include/linux/atmsvc.h
--- old/linux/include/linux/atmsvc.h	Fri Oct 18 18:40:05 1996
+++ new/linux/include/linux/atmsvc.h	Fri Oct 18 18:40:31 1996
@@ -46,6 +46,6 @@
  */
 
 #define SELECT_TOP_PCR(tp) ((tp).max_pcr && (tp).max_pcr != ATM_MAX_PCR ? \
-  (tp).max_pcr : (tp).min_pcr)
+  (tp).max_pcr : (tp).min_pcr ? (tp).min_pcr : ATM_MAX_PCR)
 
 #endif
diff -ur --new-file old/linux/include/net/sock.h new/linux/include/net/sock.h
--- old/linux/include/net/sock.h	Fri Oct 18 18:40:05 1996
+++ new/linux/include/net/sock.h	Fri Oct 18 18:40:32 1996
@@ -189,6 +189,9 @@
 				zapped,	/* In ax25 & ipx means not linked */
 				broadcast,
 				nonagle,
+#ifdef CONFIG_SCALED_WINDOWS
+				wscaling,
+#endif
 				bsdism;
 	unsigned long	        lingertime;
 	int			proc;
@@ -210,20 +213,34 @@
 	__u32			saddr;		/* Sending source */
 	__u32			rcv_saddr;	/* Bound address */
 	unsigned short		max_unacked;
+#ifdef CONFIG_SCALED_WINDOWS
+	__u32			window;
+	unsigned char		rcv_wscale;	/* our window scale */
+	unsigned char		snd_wscale;	/* their window scale */
+#else
 	unsigned short		window;
+#endif
 	__u32                   lastwin_seq;    /* sequence number when we last updated the window we offer */
 	__u32			high_seq;	/* sequence number when we did current fast retransmit */
 	volatile unsigned long  ato;            /* ack timeout */
 	volatile unsigned long  lrcvtime;       /* jiffies at last data rcv */
 	volatile unsigned long  idletime;       /* jiffies at last rcv */
+#ifdef CONFIG_SCALED_WINDOWS
+	unsigned long		bytes_rcv;
+#else
 	unsigned short		bytes_rcv;
+#endif
 /*
  *	mss is min(mtu, max_window) 
  */
 	unsigned short		mtu;       /* mss negotiated in the syn's */
 	volatile unsigned short	mss;       /* current eff. mss - can change */
 	volatile unsigned short	user_mss;  /* mss requested by user in ioctl */
+#ifdef CONFIG_SCALED_WINDOWS
+	volatile __u32		max_window;
+#else
 	volatile unsigned short	max_window;
+#endif
 	unsigned long 		window_clamp;
 	unsigned int		ssthresh;
 	unsigned short		num;
@@ -251,8 +268,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/include/net/tcp.h new/linux/include/net/tcp.h
--- old/linux/include/net/tcp.h	Tue Aug 20 17:14:55 1996
+++ new/linux/include/net/tcp.h	Fri Oct 18 18:40:32 1996
@@ -23,16 +23,26 @@
 
 /*
  * 40 is maximal IP options size
- * 4  is TCP option size (MSS)
+ * 4  is TCP option size (MSS only)
+ * 8  is TCP option size (MSS + NOP + WINDOW)
  */
+#ifdef CONFIG_SCALED_WINDOWS
+#define MAX_SYN_SIZE    (sizeof(struct iphdr) + 40 + sizeof(struct tcphdr) + 8 + MAX_HEADER + 15)
+#else
 #define MAX_SYN_SIZE	(sizeof(struct iphdr) + 40 + sizeof(struct tcphdr) + 4 + MAX_HEADER + 15)
+#endif
 #define MAX_FIN_SIZE	(sizeof(struct iphdr) + 40 + sizeof(struct tcphdr) + MAX_HEADER + 15)
 #define MAX_ACK_SIZE	(sizeof(struct iphdr) + 40 + sizeof(struct tcphdr) + MAX_HEADER + 15)
 #define MAX_RESET_SIZE	(sizeof(struct iphdr) + 40 + sizeof(struct tcphdr) + MAX_HEADER + 15)
 
-#define MAX_WINDOW	32767		/* Never offer a window over 32767 without using
-					   window scaling (not yet supported). Some poor
-					   stacks do signed 16bit maths! */
+#ifdef CONFIG_SCALED_WINDOWS
+#define MAX_WINDOW	65535
+#define MAX_WIN_SCALE	14
+#else
+#define MAX_WINDOW	32767		/* Never offer a window over 32767
+					   without using window scaling. Some
+					   poor stacks do signed 16bit maths! */
+#endif
 #define MIN_WINDOW	2048
 #define MAX_ACK_BACKLOG	2
 #define MAX_DUP_ACKS	2
@@ -82,12 +92,16 @@
 #define TCPOPT_NOP		1	/* Padding */
 #define TCPOPT_EOL		0	/* End of options */
 #define TCPOPT_MSS		2	/* Segment size negotiating */
-/*
- *	We don't use these yet, but they are for PAWS and big windows
- */
 #define TCPOPT_WINDOW		3	/* Window scaling */
 #define TCPOPT_TIMESTAMP	8	/* Better RTT estimations/PAWS */
 
+/*
+ *	TCP option lengths
+ */
+#define TCPOLEN_NOP		1
+#define TCPOLEN_MSS		4
+#define TCPOLEN_WINDOW		3
+#define TCPOLEN_TIMESTAMP	10
 
 /*
  * The next routines deal with comparing 32 bit unsigned ints
@@ -206,7 +220,11 @@
 		sk->lastwin_seq = sk->acked_seq;
 		oldwin = window;
 	}
+#ifdef CONFIG_SCALED_WINDOWS
+	return oldwin >> sk->rcv_wscale;
+#else
 	return oldwin;
+#endif
 }
 
 /*
diff -ur --new-file old/linux/net/atm/arequipa.c new/linux/net/atm/arequipa.c
--- old/linux/net/atm/arequipa.c	Fri Oct 18 18:40:05 1996
+++ new/linux/net/atm/arequipa.c	Fri Oct 18 18:40:32 1996
@@ -237,6 +237,13 @@
 	rt = upper->ip_route_cache; /* revalidate cache */
 	upper->ip_route_cache = NULL;
 	set_rt_cache(upper,rt);
+	/*
+	 * The next statement violates RFC1122, because it may change MSS when
+	 * both sides have already exchanged their SYNs. Linux doesn't mind if
+	 * this happens, but other systems might. Needs to be fixed. @@@
+	 */
+	if (ATM_SD(lower)->qos.txtp.max_sdu > RFC1483LLC_LEN)
+		upper->mtu = ATM_SD(lower)->qos.txtp.max_sdu-RFC1483LLC_LEN;
 	return 0;
 }
 
@@ -354,6 +361,7 @@
 	memset(arequipa_dev,0,sizeof(struct device)+sizeof(struct clip_priv));
 	arequipa_dev->name = "arequipa";
 	arequipa_dev->init = arequipa_init;
+	arequipa_rt.rt_dev = arequipa_dev;
 	arequipa_init(arequipa_dev);
 	return 0;
 }
diff -ur --new-file old/linux/net/atm/common.c new/linux/net/atm/common.c
--- old/linux/net/atm/common.c	Fri Oct 18 18:40:05 1996
+++ new/linux/net/atm/common.c	Fri Oct 18 18:40:31 1996
@@ -311,6 +311,8 @@
 	    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 && !vcc->qos.rxtp.traffic_class)
+		return -EINVAL;
 	if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
 	    vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
 		return -EINVAL;
@@ -833,6 +835,7 @@
 				if (optlen != sizeof(struct atm_qos))
 					return -EINVAL;
 				memcpy_fromfs(&vcc->qos,optval,optlen);
+#if 0
 				if ((vcc->qos.txtp.traffic_class == ATM_UBR &&
 				    (vcc->qos.txtp.min_pcr ||
 				    vcc->qos.txtp.max_pcr ||
@@ -844,6 +847,7 @@
 					printk(KERN_WARNING "Warning: "
 					  "semantics of ATM_UBR have changed "
 					  "with min/max_pcr != 0\n");
+#endif
 				vcc->flags |= ATM_VF_HASQOS;
 				return 0;
 			default:
diff -ur --new-file old/linux/net/atm/signaling.c new/linux/net/atm/signaling.c
--- old/linux/net/atm/signaling.c	Fri Oct 18 18:40:05 1996
+++ new/linux/net/atm/signaling.c	Fri Oct 18 18:40:31 1996
@@ -67,7 +67,7 @@
 			vcc = (struct atm_vcc *) msg->listen_vcc;
 			DPRINTK("as_indicate!!!\n");
 			if (!vcc->backlog_quota) {
-				sigd_enq(0,as_close,(struct atm_vcc *)
+				sigd_enq(0,as_reject,(struct atm_vcc *)
 				    msg->listen_vcc,NULL,NULL);
 				return 0;
 			}
diff -ur --new-file old/linux/net/atm/svc.c new/linux/net/atm/svc.c
--- old/linux/net/atm/svc.c	Fri Oct 18 18:40:05 1996
+++ new/linux/net/atm/svc.c	Fri Oct 18 18:40:31 1996
@@ -290,6 +290,7 @@
 		error = atm_connect(newsock,msg->pvc.sap_addr.itf,
 		    msg->pvc.sap_addr.vpi,msg->pvc.sap_addr.vci);
 		dev_kfree_skb(skb,FREE_WRITE);
+		old_vcc->backlog_quota++;
 		if (error) {
 			sigd_enq(NULL,as_reject,old_vcc,NULL,NULL);
 				/* @@@ should include the reason */
@@ -304,7 +305,6 @@
 			atm_release_vcc(new_vcc,1);
 			return -EUNATCH;
 		}
-		old_vcc->backlog_quota++;
 		if (!new_vcc->reply) break;
 		if (new_vcc->reply != -ERESTARTSYS) {
 			atm_release_vcc(new_vcc,1);
diff -ur --new-file old/linux/net/core/sock.c new/linux/net/core/sock.c
--- old/linux/net/core/sock.c	Sat Aug 17 19:28:10 1996
+++ new/linux/net/core/sock.c	Fri Oct 18 18:40:32 1996
@@ -172,22 +172,32 @@
 			sk->broadcast=valbool;
 			return 0;
 		case SO_SNDBUF:
+#ifdef CONFIG_SCALED_WINDOWS
+			if(val > (MAX_WINDOW << MAX_WIN_SCALE))
+				val = MAX_WINDOW << MAX_WIN_SCALE;
+#else
 			if(val > SK_WMEM_MAX*2)
 				val = SK_WMEM_MAX*2;
-			if(val < 256)
-				val = 256;
 			if(val > 65535)
 				val = 65535;
+#endif
+			if(val < 256)
+				val = 256;
 			sk->sndbuf = val;
 			return 0;
 
 		case SO_RCVBUF:
+#ifdef CONFIG_SCALED_WINDOWS
+			if(val > (MAX_WINDOW << MAX_WIN_SCALE))
+				val = MAX_WINDOW << MAX_WIN_SCALE;
+#else
 			if(val > SK_RMEM_MAX*2)
 			 	val = SK_RMEM_MAX*2;
-			if(val < 256)
-				val = 256;
 			if(val > 65535)
 				val = 65535;
+#endif
+			if(val < 256)
+				val = 256;
 			sk->rcvbuf = val;
 			return(0);
 
diff -ur --new-file old/linux/net/ipv4/Config.in new/linux/net/ipv4/Config.in
--- old/linux/net/ipv4/Config.in	Fri Jul 19 07:24:05 1996
+++ new/linux/net/ipv4/Config.in	Fri Oct 18 18:40:32 1996
@@ -42,3 +42,4 @@
 #bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF
 bool 'IP: Drop source routed frames' CONFIG_IP_NOSR
 bool 'IP: Allow large windows (not recommended if <16Mb of memory)' CONFIG_SKB_LARGE
+bool 'IP: Window scale option' CONFIG_SCALED_WINDOWS
diff -ur --new-file old/linux/net/ipv4/af_inet.c new/linux/net/ipv4/af_inet.c
--- old/linux/net/ipv4/af_inet.c	Fri Oct 18 18:40:05 1996
+++ new/linux/net/ipv4/af_inet.c	Fri Oct 18 18:40:32 1996
@@ -692,6 +692,7 @@
 	sk->rcvbuf = SK_RMEM_MAX;
 	sk->rto = TCP_TIMEOUT_INIT;		/*TCP_WRITE_TIME*/
 	sk->cong_window = 1; /* start with only sending one packet at a time. */
+	sk->ssthresh = 0x7fffffff;
 	sk->priority = 1;
 	sk->state = TCP_CLOSE;
 
diff -ur --new-file old/linux/net/ipv4/tcp.c new/linux/net/ipv4/tcp.c
--- old/linux/net/ipv4/tcp.c	Fri Oct 18 18:40:05 1996
+++ new/linux/net/ipv4/tcp.c	Fri Oct 18 18:40:32 1996
@@ -1936,6 +1936,9 @@
 	int atype;
 	struct tcphdr *t1;
 	struct rtable *rt;
+#ifdef CONFIG_SCALED_WINDOWS
+	unsigned long window;
+#endif
 
 	if (sk->state != TCP_CLOSE)
 		return(-EISCONN);
@@ -2007,6 +2010,11 @@
 	if ((rt = sk->ip_route_cache) != NULL && !sk->saddr)
 		sk->saddr = rt->rt_src;
 	sk->rcv_saddr = sk->saddr;
+#ifdef CONFIG_SCALED_WINDOWS
+	sk->snd_wscale = 0;
+	sk->rcv_wscale = 0;
+	sk->wscaling = 0;
+#endif
 
 	/*
 	 * Set up our outgoing TCP sequence number
@@ -2070,14 +2078,35 @@
 	 *	Put in the TCP options to say MTU.
 	 */
 
-	ptr = skb_put(buff,4);
-	ptr[0] = 2;
-	ptr[1] = 4;
+#ifdef CONFIG_SCALED_WINDOWS
+	window = sk->rcvbuf;
+	sk->rcv_wscale = 0;
+	while (window > MAX_WINDOW) {
+		window >>= 1;
+		sk->rcv_wscale++;
+	}
+	t1->doff += 1;		/* 4 bytes for window scaling option and NOP */
+	ptr = skb_put(buff,TCPOLEN_MSS+TCPOLEN_NOP+TCPOLEN_WINDOW);
+#else
+	ptr = skb_put(buff,TCPOLEN_MSS);
+#endif
+	ptr[0] = TCPOPT_MSS;
+	ptr[1] = TCPOLEN_MSS;
 	ptr[2] = (sk->mtu) >> 8;
 	ptr[3] = (sk->mtu) & 0xff;
-	buff->csum = csum_partial(ptr, 4, 0);
+#ifdef CONFIG_SCALED_WINDOWS
+	ptr[4] = TCPOPT_NOP;
+	ptr[5] = TCPOPT_WINDOW;
+	ptr[6] = TCPOLEN_WINDOW;
+	ptr[7] = sk->rcv_wscale;
+	buff->csum = csum_partial(ptr,TCPOLEN_MSS+TCPOLEN_NOP+TCPOLEN_WINDOW,0);
+	tcp_send_check(t1, sk->saddr, sk->daddr,
+	    sizeof(struct tcphdr)+TCPOLEN_MSS+TCPOLEN_NOP+TCPOLEN_WINDOW,buff);
+#else
+	buff->csum = csum_partial(ptr, TCPOLEN_MSS, 0);
 	tcp_send_check(t1, sk->saddr, sk->daddr,
-		  sizeof(struct tcphdr) + 4, buff);
+		  sizeof(struct tcphdr) + TCPOLEN_MSS, buff);
+#endif
 
 	/*
 	 *	This must go first otherwise a really quick response will get reset.
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 Oct 18 18:40:06 1996
+++ new/linux/net/ipv4/tcp_input.c	Fri Oct 18 18:40:32 1996
@@ -321,13 +321,22 @@
 	  			switch(opcode)
 	  			{
 	  				case TCPOPT_MSS:
-	  					if(opsize==4 && th->syn)
-	  					{
+	  					if(opsize==TCPOLEN_MSS &&
+						     th->syn) {
 	  						sk->mtu=min(sk->mtu,ntohs(*(unsigned short *)ptr));
 							mss_seen = 1;
 	  					}
 	  					break;
-		  				/* Add other options here as people feel the urge to implement stuff like large windows */
+#ifdef CONFIG_SCALED_WINDOWS
+					case TCPOPT_WINDOW:
+						if (opsize==TCPOLEN_WINDOW && th->syn) {
+						    sk->snd_wscale=min(ptr[0],
+						        MAX_WIN_SCALE);
+					  	    sk->wscaling=1;
+						}
+						break;
+#endif
+		  				/* Add other options here */
 	  			}
 	  			ptr+=opsize-2;
 	  			length-=opsize;
@@ -461,6 +470,11 @@
 	newsk->rto = TCP_TIMEOUT_INIT;
 	newsk->mdev = TCP_TIMEOUT_INIT;
 	newsk->max_window = 0;
+#ifdef CONFIG_SCALED_WINDOWS
+	newsk->snd_wscale = 0;
+	newsk->rcv_wscale = 0;
+	newsk->wscaling = 0;
+#endif
 	/*
 	 * See draft-stevens-tcpca-spec-01 for discussion of the
 	 * initialization of these values.
@@ -562,7 +576,8 @@
 	if (sk->user_mss)
 		newsk->mtu = sk->user_mss;
 	else if (rt)
-		newsk->mtu = rt->rt_mtu - sizeof(struct iphdr) - sizeof(struct tcphdr);
+		newsk->mtu = sk->ip_route_cache->rt_mtu - sizeof(struct iphdr) -
+		    sizeof(struct tcphdr); /* changed for Arequipa's MSS hack */
 	else 
 		newsk->mtu = 576 - sizeof(struct iphdr) - sizeof(struct tcphdr);
 
@@ -706,6 +721,9 @@
 	 *	Have we discovered a larger window
 	 */
 	window_seq = ntohs(th->window);
+#ifdef CONFIG_SCALED_WINDOWS
+	if (sk->wscaling && sk->snd_wscale) window_seq <<= sk->snd_wscale;
+#endif
 	if (window_seq > sk->max_window) 
 	{
   		sk->max_window = window_seq;
@@ -1193,6 +1211,10 @@
 		sk->rtt = 0;
 		sk->rto = TCP_TIMEOUT_INIT;
 		sk->mdev = TCP_TIMEOUT_INIT;
+
+#ifdef CONFIG_SCALED_WINDOWS
+		if (!sk->wscaling) sk->rcv_wscale = 0;
+#endif
 	}
 	
 	/*
diff -ur --new-file old/linux/net/ipv4/tcp_output.c new/linux/net/ipv4/tcp_output.c
--- old/linux/net/ipv4/tcp_output.c	Wed Aug  7 08:37:34 1996
+++ new/linux/net/ipv4/tcp_output.c	Fri Oct 18 18:40:32 1996
@@ -69,7 +69,22 @@
 		minwin = sk->mtu;
 	maxwin = sk->window_clamp;
 	if (!maxwin)
+#ifdef CONFIG_SCALED_WINDOWS
+	{
+		maxwin = sk->rcvbuf;
+		if (!sk->wscaling && maxwin > MAX_WINDOW) {
+			maxwin = MAX_WINDOW;
+		} else if (sk->state == TCP_SYN_RECV && sk->wscaling) {
+			sk->rcv_wscale = 0;
+			while (maxwin > MAX_WINDOW) {
+				maxwin >>= 1;
+				sk->rcv_wscale++;
+			}
+		}
+	}
+#else
 		maxwin = MAX_WINDOW;
+#endif
 	if (minwin > maxwin/2)
 		minwin = maxwin/2;
 
@@ -835,6 +850,33 @@
 	t1->rst = 0;
 	t1->psh = 0;
 	t1->ack_seq = htonl(newsk->acked_seq);
+#ifdef CONFIG_SCALED_WINDOWS
+	if (newsk->wscaling) {
+		t1->doff = 7;
+		ptr = skb_put(buff,TCPOLEN_MSS+TCPOLEN_NOP+TCPOLEN_WINDOW);
+		ptr[0] = TCPOPT_MSS;
+		ptr[1] = TCPOLEN_MSS;
+		ptr[2] = ((newsk->mtu) >> 8) & 0xff;
+		ptr[3] = (newsk->mtu) & 0xff;
+		ptr[4] = TCPOPT_NOP;
+		ptr[5] = TCPOPT_WINDOW;
+		ptr[6] = TCPOLEN_WINDOW;
+		ptr[7] = newsk->rcv_wscale;
+		buff->csum = csum_partial(ptr, TCPOLEN_MSS+TCPOLEN_NOP+
+		    TCPOLEN_WINDOW, 0);
+		tcp_send_check(t1, newsk->saddr, newsk->daddr, sizeof(*t1)+
+		    TCPOLEN_MSS+TCPOLEN_NOP+TCPOLEN_WINDOW, buff);
+	} else {
+		t1->doff = 6;
+		ptr = skb_put(buff,TCPOLEN_MSS);
+		ptr[0] = TCPOPT_MSS;
+		ptr[1] = TCPOLEN_MSS;
+		ptr[2] = ((newsk->mtu) >> 8) & 0xff;
+		ptr[3] =(newsk->mtu) & 0xff;
+		buff->csum = csum_partial(ptr, TCPOLEN_MSS, 0);
+		tcp_send_check(t1, newsk->saddr, newsk->daddr, sizeof(*t1)+TCPOLEN_MSS, buff);
+	}
+#else
 	t1->doff = sizeof(*t1)/4+1;
 	ptr = skb_put(buff,4);
 	ptr[0] = 2;
@@ -843,6 +885,7 @@
 	ptr[3] =(newsk->mtu) & 0xff;
 	buff->csum = csum_partial(ptr, 4, 0);
 	tcp_send_check(t1, newsk->saddr, newsk->daddr, sizeof(*t1)+4, buff);
+#endif
 	newsk->prot->queue_xmit(newsk, ndev, buff, 0);
 	tcp_reset_xmit_timer(newsk, TIME_WRITE , TCP_TIMEOUT_INIT);
 	skb->sk = newsk;