[PATCH 11/12] net/tcp: add support of multiple tcp connections

Mikhail Kshevetskiy mikhail.kshevetskiy at iopsys.eu
Thu Jun 27 13:39:38 CEST 2024


As we don't support ARP table in U-Boot, these
connections must come from the same host.

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy at iopsys.eu>
---
 net/Kconfig        | 10 ++++++++
 net/fastboot_tcp.c | 12 +++++++++
 net/httpd.c        | 20 ++++++++++++++-
 net/netcat.c       |  7 +++++
 net/tcp.c          | 64 ++++++++++++++++++++++++++++++----------------
 net/wget.c         |  7 +++++
 6 files changed, 97 insertions(+), 23 deletions(-)

diff --git a/net/Kconfig b/net/Kconfig
index 424c5f0dae8..e46d519f507 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -257,6 +257,16 @@ config HTTPD_COMMON
 	    * object will be stored to a memory area specified in
 	      image_load_addr variable
 
+config PROT_TCP_MAX_CONNS
+	int "Maximum number of TCP connections"
+	depends on PROT_TCP
+	default 1
+	help
+	  In some cases (like httpd support) it may be desirable
+	  to support more than one TCP connection at the time.
+	  As we don't support ARP table, these connections MUST
+	  comes from a single host.
+
 config IPV6
 	bool "IPv6 support"
 	help
diff --git a/net/fastboot_tcp.c b/net/fastboot_tcp.c
index 30eacca8d1e..dfa02709393 100644
--- a/net/fastboot_tcp.c
+++ b/net/fastboot_tcp.c
@@ -19,6 +19,12 @@ static char txbuf[sizeof(u64) + FASTBOOT_RESPONSE_LEN + 1];
 
 static u32 data_read;
 static u32 tx_last_offs, tx_last_len;
+static int connections;
+
+static void tcp_stream_on_closed(struct tcp_stream *tcp)
+{
+	connections = 0;
+}
 
 static void tcp_stream_on_rcv_nxt_update(struct tcp_stream *tcp, u32 rx_bytes)
 {
@@ -96,10 +102,16 @@ static int tcp_stream_on_create(struct tcp_stream *tcp)
 	if (tcp->lport != FASTBOOT_TCP_PORT)
 		return 0;
 
+	if (connections > 0)
+		return 0;
+
+	connections++;
+
 	data_read = 0;
 	tx_last_offs = 0;
 	tx_last_len = 0;
 
+	tcp->on_closed = tcp_stream_on_closed;
 	tcp->on_rcv_nxt_update = tcp_stream_on_rcv_nxt_update;
 	tcp->rx = tcp_stream_rx;
 	tcp->tx = tcp_stream_tx;
diff --git a/net/httpd.c b/net/httpd.c
index 31c10843a44..ad13b155912 100644
--- a/net/httpd.c
+++ b/net/httpd.c
@@ -85,6 +85,8 @@ static struct http_reply options_reply = {
 
 static int stop_server;
 static int tsize_num_hash;
+static int connections;
+static struct httpd_priv *post_id;
 
 static struct httpd_config *cfg;
 
@@ -109,6 +111,12 @@ static void tcp_stream_on_closed(struct tcp_stream *tcp)
 {
 	struct httpd_priv *priv = tcp->priv;
 
+	connections--;
+	if (tcp->priv == post_id) {
+		/* forget completed POST */
+		post_id = NULL;
+	}
+
 	if ((priv->req_state != ST_REQ_DONE) &&
 	    (priv->req_state >= ST_REQ_MPFILE)) {
 		printf("\nHTTPD: transfer was terminated\n");
@@ -119,7 +127,7 @@ static void tcp_stream_on_closed(struct tcp_stream *tcp)
 
 	free(tcp->priv);
 
-	if (stop_server)
+	if (stop_server && (connections == 0))
 		net_set_state(cfg->on_stop != NULL ?
 			      cfg->on_stop() :
 			      NETLOOP_SUCCESS);
@@ -334,6 +342,11 @@ static enum httpd_req_check http_parse_line(struct httpd_priv *priv, char *line)
 			/* expect: "\r\n--${boundary}--\r\n", so strlen() + 8 */
 			priv->post_flen -= strlen(priv->post_boundary) + 8;
 
+			if (post_id != NULL) {
+				/* do not allow multiple POST requests */
+				return HTTPD_BAD_REQ;
+			}
+
 			if (cfg->pre_post != NULL) {
 				post.addr     = NULL;
 				post.name     = priv->post_name;
@@ -345,6 +358,8 @@ static enum httpd_req_check http_parse_line(struct httpd_priv *priv, char *line)
 					return ret;
 			}
 
+			post_id = priv;
+
 			tsize_num_hash = 0;
 			printf("File: %s, %u bytes\n", priv->post_fname, priv->post_flen);
 			printf("Loading: ");
@@ -660,6 +675,7 @@ static int tcp_stream_on_create(struct tcp_stream *tcp)
 	if (priv == NULL)
 		return 0;
 
+	connections++;
 	memset(priv, 0, sizeof(struct httpd_priv));
 	priv->tcp = tcp;
 
@@ -688,6 +704,8 @@ void httpd_start(void)
 		net_set_state(NETLOOP_FAIL);
 		return;
 	}
+	post_id = NULL;
+	connections = 0;
 	stop_server = 0;
 	memset(net_server_ethaddr, 0, 6);
 	tcp_stream_set_on_create_handler(tcp_stream_on_create);
diff --git a/net/netcat.c b/net/netcat.c
index ea225c68c87..cfd39fafb61 100644
--- a/net/netcat.c
+++ b/net/netcat.c
@@ -23,6 +23,7 @@ static int			listen;
 static int			reading;
 static unsigned int		packets;
 static enum net_loop_state	netcat_loop_state;
+static int			connections;
 
 static void show_block_marker(void)
 {
@@ -34,6 +35,8 @@ static void show_block_marker(void)
 
 static void tcp_stream_on_closed(struct tcp_stream *tcp)
 {
+	connections = 0;
+
 	if (tcp->status != TCP_ERR_OK)
 		netcat_loop_state = NETLOOP_FAIL;
 
@@ -101,6 +104,10 @@ static int tcp_stream_on_create(struct tcp_stream *tcp)
 			return 0;
 	}
 
+	if (connections > 0)
+		return 0;
+
+	connections++;
 	netcat_loop_state = NETLOOP_FAIL;
 	net_boot_file_size = 0;
 	packets = 0;
diff --git a/net/tcp.c b/net/tcp.c
index 9fb80f9c2a8..c0045e32198 100644
--- a/net/tcp.c
+++ b/net/tcp.c
@@ -25,6 +25,7 @@
 #include <net.h>
 #include <net/tcp.h>
 
+#define TCP_STREAM_MAX		(CONFIG_PROT_TCP_MAX_CONNS)
 #define TCP_SEND_RETRY		3
 #define TCP_SEND_TIMEOUT	2000UL
 #define TCP_RX_INACTIVE_TIMEOUT	30000UL
@@ -34,7 +35,7 @@
 #define TCP_PACKET_OK		0
 #define TCP_PACKET_DROP		1
 
-static struct tcp_stream tcp_stream;
+static struct tcp_stream tcp_streams[TCP_STREAM_MAX];
 
 static int (*tcp_stream_on_create)(struct tcp_stream *tcp);
 
@@ -155,17 +156,24 @@ static void tcp_stream_destroy(struct tcp_stream *tcp)
 void tcp_init(void)
 {
 	static int initialized;
-	struct tcp_stream *tcp = &tcp_stream;
+	struct tcp_stream *tcp;
+	int i;
 
 	tcp_stream_on_create = NULL;
 	if (!initialized) {
 		initialized = 1;
-		memset(tcp, 0, sizeof(struct tcp_stream));
+		for (i = 0; i < TCP_STREAM_MAX; i++) {
+			tcp = &tcp_streams[i];
+			memset(tcp, 0, sizeof(struct tcp_stream));
+		}
 	}
 
-	tcp_stream_set_state(tcp, TCP_CLOSED);
-	tcp_stream_set_status(tcp, TCP_ERR_RST);
-	tcp_stream_destroy(tcp);
+	for (i = 0; i < TCP_STREAM_MAX; i++) {
+		tcp = &tcp_streams[i];
+		tcp_stream_set_state(tcp, TCP_CLOSED);
+		tcp_stream_set_status(tcp, TCP_ERR_RST);
+		tcp_stream_destroy(tcp);
+	}
 }
 
 void tcp_stream_set_on_create_handler(int (*on_create)(struct tcp_stream *))
@@ -176,28 +184,40 @@ void tcp_stream_set_on_create_handler(int (*on_create)(struct tcp_stream *))
 static struct tcp_stream *tcp_stream_add(struct in_addr rhost,
 					 u16 rport, u16 lport)
 {
-	struct tcp_stream *tcp = &tcp_stream;
+	int i;
+	struct tcp_stream *tcp;
 
-	if ((tcp_stream_on_create == NULL) ||
-	    (tcp->state != TCP_CLOSED))
+	if (tcp_stream_on_create == NULL)
 		return NULL;
 
-	tcp_stream_init(tcp, rhost, rport, lport);
-	if (!tcp_stream_on_create(tcp))
-		return NULL;
+	for (i = 0; i < TCP_STREAM_MAX; i++) {
+		tcp = &tcp_streams[i];
+		if (tcp->state != TCP_CLOSED)
+			continue;
 
-	return tcp;
+		tcp_stream_init(tcp, rhost, rport, lport);
+		if (!tcp_stream_on_create(tcp))
+			return NULL;
+
+		return tcp;
+	}
+	return NULL;
 }
 
 struct tcp_stream *tcp_stream_get(int is_new, struct in_addr rhost,
 				  u16 rport, u16 lport)
 {
-	struct tcp_stream *tcp = &tcp_stream;
+	int i;
+	struct tcp_stream *tcp;
 
-	if ((tcp->rhost.s_addr == rhost.s_addr) &&
-	    (tcp->rport == rport) &&
-	    (tcp->lport == lport))
-		return tcp;
+	for (i = 0; i < TCP_STREAM_MAX; i++) {
+		tcp = &tcp_streams[i];
+
+		if ((tcp->rhost.s_addr == rhost.s_addr) &&
+		    (tcp->rport == rport) &&
+		    (tcp->lport == lport))
+			return tcp;
+	}
 
 	return is_new ? tcp_stream_add(rhost, rport, lport) : NULL;
 }
@@ -390,12 +410,12 @@ static void tcp_stream_poll(struct tcp_stream *tcp, ulong time)
 
 void tcp_streams_poll(void)
 {
-	ulong			time;
-	struct tcp_stream	*tcp;
+	int	i;
+	ulong	time;
 
 	time = get_timer(0);
-	tcp = &tcp_stream;
-	tcp_stream_poll(tcp, time);
+	for (i = 0; i < TCP_STREAM_MAX; i++)
+		tcp_stream_poll(&tcp_streams[i], time);
 }
 
 /**
diff --git a/net/wget.c b/net/wget.c
index c91ca0bbc90..500cb58d777 100644
--- a/net/wget.c
+++ b/net/wget.c
@@ -41,6 +41,7 @@ static int wget_tsize_num_hash;
 
 static char *image_url;
 static enum net_loop_state wget_loop_state;
+static int connections;
 
 static ulong wget_load_size;
 
@@ -119,6 +120,8 @@ static void show_block_marker(void)
 
 static void tcp_stream_on_closed(struct tcp_stream *tcp)
 {
+	connections = 0;
+
 	if (tcp->status != TCP_ERR_OK)
 		wget_loop_state = NETLOOP_FAIL;
 
@@ -223,6 +226,10 @@ static int tcp_stream_on_create(struct tcp_stream *tcp)
 	    (tcp->rport != server_port))
 		return 0;
 
+	if (connections > 0)
+		return 0;
+
+	connections++;
 	tcp->max_retry_count = WGET_RETRY_COUNT;
 	tcp->initial_timeout = WGET_TIMEOUT;
 	tcp->on_closed = tcp_stream_on_closed;
-- 
2.43.0



More information about the U-Boot mailing list