netdev
[Top] [All Lists]

About TCP_MAXSEG and getsockopt()

To: linux-kernel@xxxxxxxxxxxxxxxx, linux-net@xxxxxxxxxxxxxxxx
Subject: About TCP_MAXSEG and getsockopt()
From: Anton Ghiugan <AGHIUGAN@xxxxxxxxxxxxx>
Date: Mon, 14 Aug 2000 11:04:34 -0400
Cc: alan@xxxxxxxxxxxxxxxxxxx
Organization: BLOOMBERG L.P.
Sender: owner-netdev@xxxxxxxxxxx
    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 <----------------


<Prev in Thread] Current Thread [Next in Thread>
  • About TCP_MAXSEG and getsockopt(), Anton Ghiugan <=