TCP_MAXSEG and getsockopt()

From: Anton Ghiugan (YNOT@k.ro)
Date: Mon Aug 14 2000 - 10:54:45 EST


  
    It looks like getsockopt() function call always returns a default value of zero for MSS parameter (maximum segement size) unless the user has preset it to some different value by calling setsockopt().
   Checking with the source code (net/ipv4/tcp_output.c) I have discovered that Linux uses three different variables for MSS (listed below are fragments form comments found in lines 254-274 in the above mentioned source file):
        - "user_mss is mss set by user by TCP_MAXSEG"
        - "mss_cache is current effective sending mss"
        - "mss_clamp is mss negotiated at connection setup.
                 It is minumum of user_mss and mss received with SYN"

    As you may guess getsockopt()/setsockopt() when called w/ TCP_MAXSEG operates *only* on the user_mss. While I find perfectly normal for setsockopt() to operate on (that is : modify) user_mss - since the user should be provided w/ a meaning to express what he/she wants the mss to be - I don't find any good reason why getsockopt() should return the same value.
   At least two reasons makes me belive this is an error:
         1. The user program can always remember what value he passed to setsockopt(), if any. Besides of that any system call , including getsockopt()should take longer than a in-memory access in user space.
        2. Other implementations of TCP/IP protocol notably SunOS) return correct value. See the source code at the end of this email of a small test application that has been used to verify this assumption.

     IMHO getsockopt() should return the value of mss_cache variable. Enclosed is a patch that should modify the kernel in this matter.

---------> CUT HERE <----------------
*** linux/net/ipv4/tcp.c Mon Aug 14 10:52:52 2000
--- - Mon Aug 14 11:01:58 2000
***************
*** 1764,1772 ****
        len = min(len, sizeof(int));
  
        switch(optname) {
        case TCP_MAXSEG:
! val = tp->user_mss;
                break;
        case TCP_NODELAY:
                val = (sk->nonagle == 1);
                break;
--- 1764,1772 ----
        len = min(len, sizeof(int));
  
        switch(optname) {
        case TCP_MAXSEG:
! val = tp->mss_cache;
                break;
        case TCP_NODELAY:
                val = (sk->nonagle == 1);
                break;
---------> CUT HERE <----------------

  As promised here it is the source code of the test application that helped me to detect the above bug. The program has been tested on several Linux machines including:
        2.2.14-12smp /i686
        2.2.16-3 /alpha
        
---------> CUT HERE <----------------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
int main(int argc, char **argv) {

  struct sockaddr_in dest ;
  unsigned int mss ;
  socklen_t sl;
  int s ;

  if(argc != 3) {
    fputs("USAGE: getmss.c <host_ip> <port>\n", stderr) ;
    return 0 ;
  }

  s = socket(AF_INET, SOCK_STREAM, 0) ;
  if(s == -1) {
    perror("socket");
    return -1 ;
  }
  
  memset(&dest, 0, sizeof(dest)) ;

  dest.sin_family = AF_INET ;
  dest.sin_addr.s_addr = inet_addr(argv[1]) ;
  dest.sin_port = htons(atoi(argv[2]));
  
  if(connect(s, &dest, sizeof(dest)) == -1) {
    perror("connect");
    close(s) ;
    return -1 ;
  }

  fprintf(stderr, "Connected to %s on port %s !\n",
          argv[1], argv[2]);

  mss = 0 ;
  sl = sizeof(mss) ;

  if(getsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &mss, &sl) == -1) {
    perror("getsockopt");
    close(s) ;
    return -1 ;
  }

  fprintf(stdout, "MSS = %u (sizeof(MSS) = %d)\n", mss, sl) ;
  fflush(stdout) ;
  close(s) ;

  return 0 ;
}
---------> CUT HERE <----------------

------------------------------
K Free E-mail http://www.k.ro/
by KappaNet http://www.kappa.ro/

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Aug 15 2000 - 21:00:33 EST