tcp: add TCP_MAXSEG support

Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This commit is contained in:
zhanghongyu 2023-03-08 23:43:38 +08:00 committed by Xiang Xiao
parent bd4d7a1b76
commit 93c3b8f19e
8 changed files with 101 additions and 24 deletions

View File

@ -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.
*/

View File

@ -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.

View File

@ -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

View File

@ -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;
@ -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.
@ -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.

View File

@ -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;
@ -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))
@ -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);
@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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;
@ -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))
@ -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);
@ -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 */