Skip to content

Commit

Permalink
tcp: add TCP_MAXSEG support
Browse files Browse the repository at this point in the history
Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
  • Loading branch information
zhhyu7 committed Mar 15, 2023
1 parent 58ff38d commit e8e55cb
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 24 deletions.
6 changes: 6 additions & 0 deletions include/nuttx/net/tcp.h
Expand Up @@ -137,6 +137,12 @@
#define TCP_DEFAULT_IPv4_MSS 536
#define TCP_DEFAULT_IPv6_MSS 1220

/* Minimal accepted MSS. It is (60+60+8) - (20+20).
* (MAX_IP_HDR + MAX_TCP_HDR + MIN_IP_FRAG) - (MIN_IP_HDR + MIN_TCP_HDR)
*/

#define TCP_MIN_MSS 88

/* However, we do need to make allowance for certain links such as SLIP that
* have unusually small MTUs.
*/
Expand Down
2 changes: 1 addition & 1 deletion net/socket/Kconfig
Expand Up @@ -43,7 +43,7 @@ config NET_SOCKOPTS
Enable or disable support for socket options

config NET_TCPPROTO_OPTIONS
bool
bool "TCP proto socket options"
default n
---help---
Enable or disable support for TCP protocol level socket options.
Expand Down
4 changes: 4 additions & 0 deletions net/tcp/tcp.h
Expand Up @@ -229,6 +229,10 @@ struct tcp_conn_s
uint16_t rport; /* The remoteTCP port, in network byte order */
uint16_t mss; /* Current maximum segment size for the
* connection */
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
uint16_t user_mss; /* Configured maximum segment size for the
* connection */
#endif
uint32_t rcv_adv; /* The right edge of the recv window advertized */
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
uint32_t snd_wnd; /* Sequence and acknowledgement numbers of last
Expand Down
28 changes: 22 additions & 6 deletions net/tcp/tcp_conn.c
Expand Up @@ -754,6 +754,28 @@ FAR struct tcp_conn_s *tcp_alloc(uint8_t domain)

nxsem_init(&conn->snd_sem, 0, 0);
#endif

/* Set the default value of mss to max, this field will changed when
* receive SYN.
*/

#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (domain == PF_INET)
#endif
{
conn->mss = MIN_IPv4_TCP_INITIAL_MSS;
}
#endif /* CONFIG_NET_IPv4 */

#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
conn->mss = MIN_IPv6_TCP_INITIAL_MSS;
}
#endif /* CONFIG_NET_IPv6 */
}

return conn;
Expand Down Expand Up @@ -1293,9 +1315,6 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr)
FAR const struct sockaddr_in *inaddr =
(FAR const struct sockaddr_in *)addr;

/* Save MSS and the port from the sockaddr (already in network order) */

conn->mss = MIN_IPv4_TCP_INITIAL_MSS;
conn->rport = inaddr->sin_port;

/* The sockaddr address is 32-bits in network order.
Expand Down Expand Up @@ -1327,9 +1346,6 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr)
FAR const struct sockaddr_in6 *inaddr =
(FAR const struct sockaddr_in6 *)addr;

/* Save MSS and the port from the sockaddr (already in network order) */

conn->mss = MIN_IPv6_TCP_INITIAL_MSS;
conn->rport = inaddr->sin6_port;

/* The sockaddr address is 128-bits in network order.
Expand Down
29 changes: 21 additions & 8 deletions net/tcp/tcp_getsockopt.c
Expand Up @@ -82,11 +82,6 @@
int tcp_getsockopt(FAR struct socket *psock, int option,
FAR void *value, FAR socklen_t *value_len)
{
#ifdef CONFIG_NET_TCP_KEEPALIVE
/* Keep alive options are the only TCP protocol socket option currently
* supported.
*/

FAR struct tcp_conn_s *conn;
int ret;

Expand Down Expand Up @@ -118,6 +113,7 @@ int tcp_getsockopt(FAR struct socket *psock, int option,
* all of the clones that may use the underlying connection.
*/

#ifdef CONFIG_NET_TCP_KEEPALIVE
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */
if (*value_len < sizeof(int))
Expand Down Expand Up @@ -221,6 +217,26 @@ int tcp_getsockopt(FAR struct socket *psock, int option,
ret = OK;
}
break;
#endif /* CONFIG_NET_TCP_KEEPALIVE */

case TCP_MAXSEG: /* The maximum segment size */
if (*value_len < sizeof(int))
{
/* REVISIT: POSIX says that we should truncate the value if it
* is larger than value_len. That just doesn't make sense
* to me in this case.
*/

ret = -EINVAL;
}
else
{
FAR int *mss = (FAR int *)value;
*mss = conn->mss;
*value_len = sizeof(int);
ret = OK;
}
break;

default:
nerr("ERROR: Unrecognized TCP option: %d\n", option);
Expand All @@ -229,9 +245,6 @@ int tcp_getsockopt(FAR struct socket *psock, int option,
}

return ret;
#else
return -ENOPROTOOPT;
#endif /* CONFIG_NET_TCP_KEEPALIVE */
}

#endif /* CONFIG_NET_TCPPROTO_OPTIONS */
7 changes: 7 additions & 0 deletions net/tcp/tcp_input.c
Expand Up @@ -586,6 +586,13 @@ static void tcp_parse_option(FAR struct net_driver_s *dev,

tmp16 = ((uint16_t)IPDATA(tcpiplen + 2 + i) << 8) |
(uint16_t)IPDATA(tcpiplen + 3 + i);
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
if (conn->user_mss > 0 && conn->user_mss < tcp_mss)
{
tcp_mss = conn->user_mss;
}
#endif

conn->mss = tmp16 > tcp_mss ? tcp_mss : tmp16;
}
#ifdef CONFIG_NET_TCP_WINDOW_SCALE
Expand Down
11 changes: 10 additions & 1 deletion net/tcp/tcp_send.c
Expand Up @@ -585,7 +585,16 @@ void tcp_synack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,

/* Set the packet length for the TCP Maximum Segment Size */

tcp_mss = tcp_rx_mss(dev);
#ifdef CONFIG_NET_TCPPROTO_OPTIONS
if (conn->user_mss != 0 && conn->user_mss < tcp_rx_mss(dev))
{
tcp_mss = conn->user_mss;
}
else
#endif
{
tcp_mss = tcp_rx_mss(dev);
}

/* Save the ACK bits */

Expand Down
38 changes: 30 additions & 8 deletions net/tcp/tcp_setsockopt.c
Expand Up @@ -72,11 +72,6 @@
int tcp_setsockopt(FAR struct socket *psock, int option,
FAR const void *value, socklen_t value_len)
{
#ifdef CONFIG_NET_TCP_KEEPALIVE
/* Keep alive options are the only TCP protocol socket option currently
* supported.
*/

FAR struct tcp_conn_s *conn;
int ret = OK;

Expand Down Expand Up @@ -107,6 +102,7 @@ int tcp_setsockopt(FAR struct socket *psock, int option,
* all of the clones that may use the underlying connection.
*/

#ifdef CONFIG_NET_TCP_KEEPALIVE
case SO_KEEPALIVE: /* Verifies TCP connections active by enabling the
* periodic transmission of probes */
if (value_len != sizeof(int))
Expand Down Expand Up @@ -233,6 +229,35 @@ int tcp_setsockopt(FAR struct socket *psock, int option,
}
}
break;
#endif /* CONFIG_NET_TCP_KEEPALIVE */

case TCP_MAXSEG: /* The maximum segment size */
if (value_len != sizeof(int))
{
ret = -EFAULT;
}
else
{
int mss = *(FAR int *)value;

if (conn->tcpstateflags != TCP_ALLOCATED)
{
/* Set TCP_MAXSEG in the wrong state, direct return success */

return OK;
}

if (mss < TCP_MIN_MSS || mss > UINT16_MAX)
{
nerr("ERROR: TCP_MAXSEG value out of range: %d\n", mss);
return -EINVAL;
}
else
{
conn->user_mss = mss;
}
}
break;

default:
nerr("ERROR: Unrecognized TCP option: %d\n", option);
Expand All @@ -241,9 +266,6 @@ int tcp_setsockopt(FAR struct socket *psock, int option,
}

return ret;
#else
return -ENOPROTOOPT;
#endif /* CONFIG_NET_TCP_KEEPALIVE */
}

#endif /* CONFIG_NET_TCPPROTO_OPTIONS */

0 comments on commit e8e55cb

Please sign in to comment.