TCP Window Scaling Option

This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

  • TCP Window Scaling Option

    embOS/IP's support for TCP window scaling is incomplete and I think there may be a bug in the code that prevents proper support.

    Window scaling allows a host to specify receive/send windows that are larger than 65535 bytes by specifying an optional scaling factor during the connection (SYN) phase. This is useful in cases where the receiver has a lot of memory (say a PC) and the sender has a lot of data to send quickly. Of course, the sender needs a fair amount of memory too in order to hold the TCP packets that are waiting for ACKs. However, many of today's MCUs have external memory controllers that can access many megabytes of RAM (e.g., NXP LPC246).

    According to pages 864 - 866 of "TCP/IP Illustrated - Volume 2: The Implementation" by Wright & Stevens, a client (connecting) host can request window scaling by specifying a 3-byte option in the TCP options portion of the header. In order for the option to be accepted, however, the server host must respond with the window scaling option in its SYN packet. embOS/IP includes some fo the code necessary for supporting this capability, but it's incomplete. The changes I believe are necessary (there may be more) to get embOS/IP to respond properly are

    1) IP_socket.c, sosetopt() function

    Add an additional SO_WINSCALE case to the switch statement (line 16). Also, after creating a socket, your code must call setsockopt( sock, SOL_SOCKET, SO_WINSCALE, NULL, 0 ); to enable window scaling support.

    C Source Code

    1. switch (optname) {
    2. case SO_LINGER:
    3. so->so_linger = (short) ((struct linger *)arg)->l_linger;
    4. arg = &((struct linger *)arg)->l_onoff;
    5. // Fall through
    6. case SO_KEEPALIVE:
    7. case SO_DONTROUTE:
    8. case SO_BROADCAST:
    9. case SO_REUSEADDR:
    10. case SO_OOBINLINE:
    11. case SO_TCPSACK:
    12. case SO_NOSLOWSTART:
    13. #ifdef SUPPORT_SO_FULLMSS
    14. case SO_FULLMSS:
    15. #endif
    16. case SO_WINSCALE:
    17. if (*(int *)arg) {
    18. so->so_options |= optname;
    19. } else {
    20. so->so_options &= ~optname;
    21. }
    22. break;
    Display All


    2) IP_TCP_in.c, _HandleOptions() function

    Fix what I think is a bug by changing this (line 6)

    C Source Code

    1. //
    2. // Compute True MSS based on mss and Option lne
    3. //
    4. if (ti->ti_flags & TH_SYN) { /* MSS only on SYN */
    5. int OptLen = 0;
    6. if (tp->t_flags &= TF_TIMESTAMP) {
    7. OptLen += 12;
    8. }
    9. tp->OptLen = OptLen;
    10. tp->TrueMSS = tp->Mss - OptLen;
    11. tp->snd_cwnd = 0xFFFF; // Use max. value initially
    12. }
    13. return;
    Display All


    to this (line 6)

    C Source Code

    1. //
    2. // Compute True MSS based on mss and Option lne
    3. //
    4. if (ti->ti_flags & TH_SYN) { /* MSS only on SYN */
    5. int OptLen = 0;
    6. if (tp->t_flags & TF_TIMESTAMP) {
    7. OptLen += 12;
    8. }
    9. tp->OptLen = OptLen;
    10. tp->TrueMSS = tp->Mss - OptLen;
    11. tp->snd_cwnd = 0xFFFF; // Use max. value initially
    12. }
    13. return;
    Display All


    3) If window scaling is going to be supported generally, then the SO_WINSCALE option should be documented in the user manual.

    I have tested changes (1) & (2) with a Windows XP PC as a client requesting 8x window scaling and observed the results in WireShark. The window scaling options do appear in the SYN packets as expected. Also, using a debugger, I have observed that the embOS/IP TCP control block field "snd_wnd" is expanded by the scaling factor as requested by the PC. Further testing, however, is required to ensure that TCP packets are sent, ACKed and disposed of properly.