Index: sys/netinet/tcp.h =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp.h,v retrieving revision 1.40 diff -p -u -I__FBSDID -I$FreeBSD -r1.40 tcp.h --- sys/netinet/tcp.h 25 May 2007 21:28:49 -0000 1.40 +++ sys/netinet/tcp.h 18 Jun 2008 05:36:20 -0000 @@ -78,6 +78,8 @@ struct tcphdr { #define TCPOPT_EOL 0 #define TCPOLEN_EOL 1 +#define TCPOPT_PAD 0 /* padding after EOL */ +#define TCPOLEN_PAD 1 #define TCPOPT_NOP 1 #define TCPOLEN_NOP 1 #define TCPOPT_MAXSEG 2 Index: sys/netinet/tcp_output.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_output.c,v retrieving revision 1.141.2.3 diff -p -u -I__FBSDID -I$FreeBSD -r1.141.2.3 tcp_output.c --- sys/netinet/tcp_output.c 5 Dec 2007 10:37:17 -0000 1.141.2.3 +++ sys/netinet/tcp_output.c 18 Jun 2008 05:36:21 -0000 @@ -1280,12 +1280,16 @@ tcp_addoptions(struct tcpopt *to, u_char for (mask = 1; mask < TOF_MAXOPT; mask <<= 1) { if ((to->to_flags & mask) != mask) continue; + if (optlen == TCP_MAXOLEN) + break; switch (to->to_flags & mask) { case TOF_MSS: while (optlen % 4) { optlen += TCPOLEN_NOP; *optp++ = TCPOPT_NOP; } + if (TCP_MAXOLEN - optlen < TCPOLEN_MAXSEG) + continue; optlen += TCPOLEN_MAXSEG; *optp++ = TCPOPT_MAXSEG; *optp++ = TCPOLEN_MAXSEG; @@ -1298,6 +1302,8 @@ tcp_addoptions(struct tcpopt *to, u_char optlen += TCPOLEN_NOP; *optp++ = TCPOPT_NOP; } + if (TCP_MAXOLEN - optlen < TCPOLEN_WINDOW) + continue; optlen += TCPOLEN_WINDOW; *optp++ = TCPOPT_WINDOW; *optp++ = TCPOLEN_WINDOW; @@ -1308,6 +1314,8 @@ tcp_addoptions(struct tcpopt *to, u_char optlen += TCPOLEN_NOP; *optp++ = TCPOPT_NOP; } + if (TCP_MAXOLEN - optlen < TCPOLEN_SACK_PERMITTED) + continue; optlen += TCPOLEN_SACK_PERMITTED; *optp++ = TCPOPT_SACK_PERMITTED; *optp++ = TCPOLEN_SACK_PERMITTED; @@ -1317,6 +1325,8 @@ tcp_addoptions(struct tcpopt *to, u_char optlen += TCPOLEN_NOP; *optp++ = TCPOPT_NOP; } + if (TCP_MAXOLEN - optlen < TCPOLEN_TIMESTAMP) + continue; optlen += TCPOLEN_TIMESTAMP; *optp++ = TCPOPT_TIMESTAMP; *optp++ = TCPOLEN_TIMESTAMP; @@ -1355,7 +1365,7 @@ tcp_addoptions(struct tcpopt *to, u_char optlen += TCPOLEN_NOP; *optp++ = TCPOPT_NOP; } - if (TCP_MAXOLEN - optlen < 2 + TCPOLEN_SACK) + if (TCP_MAXOLEN - optlen < TCPOLEN_SACKHDR + TCPOLEN_SACK) continue; optlen += TCPOLEN_SACKHDR; *optp++ = TCPOPT_SACK; @@ -1386,9 +1396,15 @@ tcp_addoptions(struct tcpopt *to, u_char optlen += TCPOLEN_EOL; *optp++ = TCPOPT_EOL; } + /* + * According to RFC 793 (STD0007): + * "The content of the header beyond the End-of-Option option + * must be header padding (i.e., zero)." + * and later: "The padding is composed of zeros." + */ while (optlen % 4) { - optlen += TCPOLEN_NOP; - *optp++ = TCPOPT_NOP; + optlen += TCPOLEN_PAD; + *optp++ = TCPOPT_PAD; } KASSERT(optlen <= TCP_MAXOLEN, ("%s: TCP options too long", __func__));