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;