[RESEND PATCH v3 9/9] net/netcat: add netcat over tcp support
Simon Glass
sjg at chromium.org
Sat Aug 17 17:58:27 CEST 2024
Hi Mikhail,
On Wed, 14 Aug 2024 at 04:32, Mikhail Kshevetskiy
<mikhail.kshevetskiy at iopsys.eu> wrote:
>
> This patch adds downloading/uploading of data with netcat.
> Client/server mode both supported.
>
> Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy at 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
Is there a way to test this?
>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 978f44eda42..abcd003f7f1 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -2007,6 +2007,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 53ce2bc5d0c..6ac81415f8a 100644
> --- a/cmd/net.c
> +++ b/cmd/net.c
> @@ -206,6 +206,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)
!strcmp
> + return netboot_common(NETCAT_LOAD, cmdtp, argc - 1, argv + 1);
> + else if (strcmp(argv[1], "store") == 0)
We normally use 'save' in U-Boot.
> + 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];
> @@ -323,16 +345,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:
> @@ -354,7 +377,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 {
> @@ -365,7 +389,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 b0ce13e0a9d..5ec826209f0 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -515,7 +515,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.kshevetskiy at 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 86182cc504e..0e05a8f2336 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -108,6 +108,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"
> @@ -564,6 +565,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.kshevetskiy at 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);
Can you add a comment as to why the \n is needed at the start?
> + 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)
function comment
> +{
> + 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;
should return an error code
> + }
> + tcp_stream_put(tcp);
This looks like a nice API!
> + }
> +}
> +
> +void netcat_load_start(void)
> +{
> + reading = 1;
> + return netcat_start();
> +}
> +
> +void netcat_store_start(void)
> +{
> + reading = 0;
> + return netcat_start();
> +}
> --
> 2.39.2
>
Regards,
Simon
More information about the U-Boot
mailing list