Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!cornell!uw-beaver!uw-entropy!quick!srg From: srg@quick.COM (Spencer Garrett) Newsgroups: comp.protocols.tcp-ip Subject: Re: 4.X implementations of TCP, initial sequence numbers, and windows Keywords: sequence numbers, windows, SEQ_GT Message-ID: <7016@quick.COM> Date: 28 Oct 89 20:52:49 GMT References: <2642@lll-lcc.UUCP> Organization: Quicksilver Engineering, Seattle Lines: 39 In article <2642@lll-lcc.UUCP>, rwolski@lll-lcc.UUCP (Richard Wolski) writes: > > if(win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) > tp->rcv_adv = tp->rcv_nxt + win; > > What we notice is that another vendor's implementation of TCP chooses an > initial sending sequence number with the sign bit set (sometimes) and that > the rcv_adv field in the tcpcb always remains 0. I think the following thing > is happening. SEQ_GT is defined as: > > #define SEQ_GT(a,b) ((int)((a)-(b)) > 0) > > When expanded in the above code, (a) has the sign bit set, (b) is zero, so the > test fails and rcv_adv never gets set properly. This manifests itself > as unusually large windows where one would not expect them. > > My first question: Am I reading this right? I checked the code to set the > iss on the sending side, and it periodically increments a global variable > which eventually results in a negative number (when viewed as an int). This is the key. Sequence numbers are unsigned values which must be interpreted modulo 2**32. Thus, the sequence number following 0xffffffff is 0, and the difference of these two is 1. On a machine with 32 bit ints this can be accomplished by subtracting the two sequence numbers, ignoring overflow, and casting the result to a signed integer. If the int's on your machine aren't exactly 32 bits long, however, this algorithm won't work correctly. My guess is that your code isn't initializing tp->rcv_adv during TCP startup. You should be setting rcv_nxt from the initial sequence number you get from the peer host in the SYN packet (plus 1 for the SYN), and you should initialize rcv_adv to rcv_nxt plus your initial offered window. The code you've quoted above only sets rcv_adv when it thinks it's extending the window. If rcv_adv is zero and rcv_nxt has its "sign" bit set, but isn't close to the top of the range, then the window looks huge, so your code never thinks it should be extended. If the sign bit were clear, however, then the window would appear negative, and your code would happily reset it the first time through.