rwolski@lll-lcc.UUCP (Richard Wolski) (10/26/89)
Hello everyone. I have a BSD implementation question regarding the initial sequence number and the advertised window. In some of the BSD code that we have (vendors will remain nameless to protect the innocent) the following piece of code appears: 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). But wait, there's more... We looked further at the sender's code for setting iss and saw the following statements: #ifdef TCP_COMPAT_42 if((int)tcp_iss < 0) tcp_iss = 0; /* XXX */ #endif This makes me believe that the problem is somehow fixed at 4.3. Is that true? We looked at yet another vendor's implementation which was supposed to be 4.3, and nothing seems to be different. Any thoughts that you might have in this matter will be gratefully appreciated, and I apologize if I am asking for the answer to a question that everybody except me is privy to. Rich Wolski rwolski@lll-lcc.llnl.gov inter-net (415)423-8594 bell-net P.O. Box 808, L-60 mail-net Livermore, CA 94538
srg@quick.COM (Spencer Garrett) (10/29/89)
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.