You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2023/04/21 17:42:55 UTC
[nuttx] 02/02: tcp: add TCP_MAXSEG support
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 93c3b8f19e0095493543105ce38148ce66588457
Author: zhanghongyu <zh...@xiaomi.com>
AuthorDate: Wed Mar 8 23:43:38 2023 +0800
tcp: add TCP_MAXSEG support
Signed-off-by: zhanghongyu <zh...@xiaomi.com>
---
include/nuttx/net/tcp.h | 6 ++++++
net/socket/Kconfig | 2 +-
net/tcp/tcp.h | 4 ++++
net/tcp/tcp_conn.c | 28 ++++++++++++++++++++++------
net/tcp/tcp_getsockopt.c | 29 +++++++++++++++++++++--------
net/tcp/tcp_input.c | 7 +++++++
net/tcp/tcp_send.c | 11 ++++++++++-
net/tcp/tcp_setsockopt.c | 38 ++++++++++++++++++++++++++++++--------
8 files changed, 101 insertions(+), 24 deletions(-)
diff --git a/include/nuttx/net/tcp.h b/include/nuttx/net/tcp.h
index 83e4fa1b05..9a76af558a 100644
--- a/include/nuttx/net/tcp.h
+++ b/include/nuttx/net/tcp.h
@@ -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.
*/
diff --git a/net/socket/Kconfig b/net/socket/Kconfig
index 6877dc3d5f..ada47c6de8 100644
--- a/net/socket/Kconfig
+++ b/net/socket/Kconfig
@@ -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.
diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h
index aae70be268..c133882542 100644
--- a/net/tcp/tcp.h
+++ b/net/tcp/tcp.h
@@ -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
diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c
index 329196e5ad..b5658e019d 100644
--- a/net/tcp/tcp_conn.c
+++ b/net/tcp/tcp_conn.c
@@ -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.
diff --git a/net/tcp/tcp_getsockopt.c b/net/tcp/tcp_getsockopt.c
index 7d815f6a5f..c8d3d7142f 100644
--- a/net/tcp/tcp_getsockopt.c
+++ b/net/tcp/tcp_getsockopt.c
@@ -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 */
diff --git a/net/tcp/tcp_input.c b/net/tcp/tcp_input.c
index ce9fc4f018..06d21a07c3 100644
--- a/net/tcp/tcp_input.c
+++ b/net/tcp/tcp_input.c
@@ -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
diff --git a/net/tcp/tcp_send.c b/net/tcp/tcp_send.c
index 416e0e5f21..edd6422c13 100644
--- a/net/tcp/tcp_send.c
+++ b/net/tcp/tcp_send.c
@@ -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 */
diff --git a/net/tcp/tcp_setsockopt.c b/net/tcp/tcp_setsockopt.c
index d447ea84b1..1123d71e92 100644
--- a/net/tcp/tcp_setsockopt.c
+++ b/net/tcp/tcp_setsockopt.c
@@ -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 */