This patch adds downloading/uploading of data with netcat.
Client/server mode both supported.

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevets...@iopsys.eu>
---
 cmd/Kconfig          |   7 ++
 cmd/net.c            |  34 +++++++--
 include/net.h        |   2 +-
 include/net/netcat.h |  20 ++++++
 net/Makefile         |   1 +
 net/net.c            |   9 +++
 net/netcat.c         | 159 +++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 226 insertions(+), 6 deletions(-)
 create mode 100644 include/net/netcat.h
 create mode 100644 net/netcat.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 6834bbd82f3..00cc13e2006 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1990,6 +1990,13 @@ config CMD_WGET
          wget is a simple command to download kernel, or other files,
          from a http server over TCP.
 
+config CMD_NETCAT
+       bool "netcat"
+       select PROT_TCP
+       help
+         netcat is a simple command to load/store kernel, or other files,
+         using netcat like manner over TCP.
+
 config CMD_MII
        bool "mii"
        imply CMD_MDIO
diff --git a/cmd/net.c b/cmd/net.c
index d407d8320a3..ecc1b49f52f 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -208,6 +208,28 @@ U_BOOT_CMD(
 );
 #endif
 
+#if defined(CONFIG_CMD_NETCAT)
+static int do_netcat(struct cmd_tbl *cmdtp, int flag, int argc, char *const 
argv[])
+{
+       if (argc < 2)
+               return 1;
+
+       if (strcmp(argv[1], "load") == 0)
+               return netboot_common(NETCAT_LOAD, cmdtp, argc - 1, argv + 1);
+       else if (strcmp(argv[1], "store") == 0)
+               return netboot_common(NETCAT_STORE, cmdtp, argc - 1, argv + 1);
+       else
+               return 1;
+}
+
+U_BOOT_CMD(
+       netcat,   5,      1,      do_netcat,
+       "load/store data via tcp netcat utility",
+       "load [loadAddress] [[hostIPaddr:]port]\n"
+       "store Address Size [[hostIPaddr:]port]\n"
+);
+#endif
+
 static void netboot_update_env(void)
 {
        char tmp[46];
@@ -325,16 +347,17 @@ static int parse_args(enum proto_t proto, int argc, char 
*const argv[])
 
        switch (argc) {
        case 1:
-               if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT)
+               if ((IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) ||
+                   (IS_ENABLED(CONFIG_CMD_NETCAT) && proto == NETCAT_STORE))
                        return 1;
-
                /* refresh bootfile name from env */
                copy_filename(net_boot_file_name, env_get("bootfile"),
                              sizeof(net_boot_file_name));
                break;
 
        case 2:
-               if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT)
+               if ((IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) ||
+                   (IS_ENABLED(CONFIG_CMD_NETCAT) && proto == NETCAT_STORE))
                        return 1;
                /*
                 * Only one arg - accept two forms:
@@ -356,7 +379,8 @@ static int parse_args(enum proto_t proto, int argc, char 
*const argv[])
                break;
 
        case 3:
-               if (IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) {
+               if ((IS_ENABLED(CONFIG_CMD_TFTPPUT) && proto == TFTPPUT) ||
+                   (IS_ENABLED(CONFIG_CMD_NETCAT) && proto == NETCAT_STORE)) {
                        if (parse_addr_size(argv))
                                return 1;
                } else {
@@ -367,7 +391,7 @@ static int parse_args(enum proto_t proto, int argc, char 
*const argv[])
                }
                break;
 
-#ifdef CONFIG_CMD_TFTPPUT
+#if defined(CONFIG_CMD_TFTPPUT) || defined(CONFIG_CMD_NETCAT)
        case 4:
                if (parse_addr_size(argv))
                        return 1;
diff --git a/include/net.h b/include/net.h
index fe645245f0f..235396a171b 100644
--- a/include/net.h
+++ b/include/net.h
@@ -516,7 +516,7 @@ extern int          net_restart_wrap;       /* Tried all 
network devices */
 enum proto_t {
        BOOTP, RARP, ARP, TFTPGET, DHCP, DHCP6, PING, PING6, DNS, NFS, CDP,
        NETCONS, SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT_UDP, FASTBOOT_TCP,
-       WOL, UDP, NCSI, WGET, RS
+       WOL, UDP, NCSI, WGET, NETCAT_LOAD, NETCAT_STORE, RS
 };
 
 extern char    net_boot_file_name[1024];/* Boot File name */
diff --git a/include/net/netcat.h b/include/net/netcat.h
new file mode 100644
index 00000000000..09470e7f0ce
--- /dev/null
+++ b/include/net/netcat.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: BSD-2-Clause
+ *
+ * netcat include file
+ * Copyright (C) 2024 IOPSYS Software Solutions AB
+ * Author: Mikhail Kshevetskiy <mikhail.kshevets...@iopsys.eu>
+ */
+#ifndef __NET_NETCAT_TCP_H__
+#define __NET_NETCAT_TCP_H__
+
+/**
+ * netcat_load_start() - begin netcat in loading mode
+ */
+void netcat_load_start(void);
+
+/**
+ * netcat_store_start() - begin netcat in data storing mode
+ */
+void netcat_store_start(void);
+
+#endif /* __NET_NETCAT_TCP_H__ */
diff --git a/net/Makefile b/net/Makefile
index 64ab7ec740a..dac7b4859fb 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_CMD_WOL)  += wol.o
 obj-$(CONFIG_PROT_UDP) += udp.o
 obj-$(CONFIG_PROT_TCP) += tcp.o
 obj-$(CONFIG_CMD_WGET) += wget.o
+obj-$(CONFIG_CMD_NETCAT) += netcat.o
 
 # Disable this warning as it is triggered by:
 # sprintf(buf, index ? "foo%d" : "foo", index)
diff --git a/net/net.c b/net/net.c
index 0fca11d3e8c..809fe5c4792 100644
--- a/net/net.c
+++ b/net/net.c
@@ -110,6 +110,7 @@
 #include <test/test.h>
 #include <net/tcp.h>
 #include <net/wget.h>
+#include <net/netcat.h>
 #include "arp.h"
 #include "bootp.h"
 #include "cdp.h"
@@ -566,6 +567,14 @@ restart:
                        wget_start();
                        break;
 #endif
+#if defined(CONFIG_CMD_NETCAT)
+               case NETCAT_LOAD:
+                       netcat_load_start();
+                       break;
+               case NETCAT_STORE:
+                       netcat_store_start();
+                       break;
+#endif
 #if defined(CONFIG_CMD_CDP)
                case CDP:
                        cdp_start();
diff --git a/net/netcat.c b/net/netcat.c
new file mode 100644
index 00000000000..ea225c68c87
--- /dev/null
+++ b/net/netcat.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * netcat support driver
+ * Copyright (C) 2024 IOPSYS Software Solutions AB
+ * Author: Mikhail Kshevetskiy <mikhail.kshevets...@iopsys.eu>
+ */
+
+#include <command.h>
+#include <display_options.h>
+#include <env.h>
+#include <image.h>
+#include <mapmem.h>
+#include <net.h>
+#include <net/tcp.h>
+#include <net/netcat.h>
+
+#define HASHES_PER_LINE                65
+
+static struct in_addr          server_ip;
+static u16                     server_port;
+static u16                     local_port;
+static int                     listen;
+static int                     reading;
+static unsigned int            packets;
+static enum net_loop_state     netcat_loop_state;
+
+static void show_block_marker(void)
+{
+       if ((packets % 10) == 0)
+               putc('#');
+       else if (((packets + 1) % (10 * HASHES_PER_LINE)) == 0)
+               puts("\n");
+}
+
+static void tcp_stream_on_closed(struct tcp_stream *tcp)
+{
+       if (tcp->status != TCP_ERR_OK)
+               netcat_loop_state = NETLOOP_FAIL;
+
+       if (netcat_loop_state != NETLOOP_SUCCESS)
+               printf("\nnetcat: Transfer Fail, TCP status - %d\n", 
tcp->status);
+       else
+               printf("\nPackets %s %d, Transfer Successful\n",
+                      reading ? "received" : "transmitted", packets);
+       net_set_state(netcat_loop_state);
+}
+
+static void tcp_stream_on_rcv_nxt_update(struct tcp_stream *tcp, u32 rx_bytes)
+{
+       net_boot_file_size = rx_bytes;
+       show_block_marker();
+}
+
+static void tcp_stream_on_snd_una_update(struct tcp_stream *tcp, u32 tx_bytes)
+{
+       show_block_marker();
+       if (tx_bytes == image_save_size)
+               tcp_stream_close(tcp);
+}
+
+static void tcp_stream_on_established(struct tcp_stream *tcp)
+{
+       netcat_loop_state = NETLOOP_SUCCESS;
+}
+
+static u32 tcp_stream_rx(struct tcp_stream *tcp, u32 rx_offs, void *buf, u32 
len)
+{
+       void *ptr;
+
+       packets++;
+       ptr = map_sysmem(image_load_addr + rx_offs, len);
+       memcpy(ptr, buf, len);
+       unmap_sysmem(ptr);
+       return len;
+}
+
+static u32 tcp_stream_tx(struct tcp_stream *tcp, u32 tx_offs, void *buf, u32 
maxlen)
+{
+       void *ptr;
+
+       if (tx_offs + maxlen > image_save_size)
+               maxlen = image_save_size - tx_offs;
+       if (maxlen == 0)
+               return 0;
+
+       packets++;
+       ptr = map_sysmem(image_save_addr + tx_offs, maxlen);
+       memcpy(buf, ptr, maxlen);
+       unmap_sysmem(ptr);
+       return maxlen;
+}
+
+static int tcp_stream_on_create(struct tcp_stream *tcp)
+{
+       if (listen) {
+               if (tcp->lport != local_port)
+                       return 0;
+       } else {
+               if ((tcp->rhost.s_addr != server_ip.s_addr) ||
+                   (tcp->rport != server_port))
+                       return 0;
+       }
+
+       netcat_loop_state = NETLOOP_FAIL;
+       net_boot_file_size = 0;
+       packets = 0;
+
+       tcp->on_closed = tcp_stream_on_closed;
+       tcp->on_established = tcp_stream_on_established;
+       if (reading) {
+               tcp->on_rcv_nxt_update = tcp_stream_on_rcv_nxt_update;
+               tcp->rx = tcp_stream_rx;
+       } else {
+               tcp->on_snd_una_update = tcp_stream_on_snd_una_update;
+               tcp->tx = tcp_stream_tx;
+       }
+       return 1;
+}
+
+static void netcat_start(void)
+{
+       struct tcp_stream *tcp;
+
+       memset(net_server_ethaddr, 0, 6);
+       tcp_stream_set_on_create_handler(tcp_stream_on_create);
+
+       if (strchr(net_boot_file_name, ':') == NULL) {
+               listen = 1;
+               printf("Listening on port %s...\n", net_boot_file_name);
+
+               local_port = dectoul(net_boot_file_name, NULL);
+       } else {
+               listen = 0;
+               printf("Connecting to %s...\n", net_boot_file_name);
+
+               server_ip = string_to_ip(net_boot_file_name);
+               server_port = dectoul(strchr(net_boot_file_name, ':') + 1, 
NULL);
+
+               tcp = tcp_stream_connect(server_ip, server_port);
+               if (tcp == NULL) {
+                       printf("No free tcp streams\n");
+                       net_set_state(NETLOOP_FAIL);
+                       return;
+               }
+               tcp_stream_put(tcp);
+       }
+}
+
+void netcat_load_start(void)
+{
+       reading = 1;
+       return netcat_start();
+}
+
+void netcat_store_start(void)
+{
+       reading = 0;
+       return netcat_start();
+}
-- 
2.43.0

Reply via email to