Message ID | 20240909222720.2563118-11-mikhail.kshevetskiy@iopsys.eu |
---|---|
State | Superseded |
Delegated to: | Ramon Fried |
Headers | show |
Series | net: tcp: improve tcp support | expand |
Hi Mikhail, On Mon, 9 Sept 2024 at 16:27, Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu> wrote: > > This patch adds downloading/uploading of data with netcat. > Client/server mode both supported. > > How to test: > ============ > netcat-openbsd=1.219-1 from debian were used for a tests > > a) Load data from remote host. > * U-Boot listen on tcp port 3456 > * PC connects > > u-boot: netcat load ${loadaddr} 3456 > PC: netcat -q1 ${UBOOT_IP} 3456 < image.itb > > b) Load data from remote host. > * PC listen on tcp port 3456 > * U-Boot connects > > PC: netcat -q1 -l -p 3456 < image.itb > u-boot: netcat load ${loadaddr} ${PC_IP}:3456 > > c) Save data to remote host > * U-Boot listen on tcp port 3456 > * PC connects > > u-boot: netcat save ${loadaddr} ${data_size_in_hex} 3456 > PC: netcat -w1 ${UBOOT_IP} 3456 >image.itb > > d) Save data to remote host > * PC listen on tcp port 3456 > * U-Boot connects > > PC: netcat -w1 -l -p 3456 >image.itb > u-boot: netcat save ${loadaddr} ${data_size_in_hex} ${PC_IP}:3456 > > Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@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 | 181 +++++++++++++++++++++++++++++++++++++++++++ > 7 files changed, 248 insertions(+), 6 deletions(-) > create mode 100644 include/net/netcat.h > create mode 100644 net/netcat.c Reviewed-by: Simon Glass <sjg@chromium.org> nits below > > 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. netcat-like Please add a reference to the protocol or the 'netcat' tool or both. Help must be at least 3 lines. > + > config CMD_MII > bool "mii" > imply CMD_MDIO > diff --git a/cmd/net.c b/cmd/net.c > index 53ce2bc5d0c..364139ec5b9 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")) > + return netboot_common(NETCAT_LOAD, cmdtp, argc - 1, argv + 1); > + else if (!strcmp(argv[1], "save")) > + return netboot_common(NETCAT_SAVE, cmdtp, argc - 1, argv + 1); > + else > + return 1; > +} > + Needs longhelp > +U_BOOT_CMD( > + netcat, 5, 1, do_netcat, > + "load/store data via tcp netcat utility", > + "load [loadAddress] [[hostIPaddr:]port]\n" > + "save 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_SAVE)) > 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_SAVE)) > 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_SAVE)) { > 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..0af6493788a 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_SAVE, 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..d8e09aaaa55 > --- /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@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_save_start() - begin netcat in data saving mode > + */ > +void netcat_save_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..d81604a57ce 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> That should be above net/tcp > #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_SAVE: > + netcat_save_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..633afe5c60b > --- /dev/null > +++ b/net/netcat.c > @@ -0,0 +1,181 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * netcat support driver > + * Copyright (C) 2024 IOPSYS Software Solutions AB > + * Author: Mikhail Kshevetskiy <mikhail.kshevetskiy@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) else if (!((packets + 1) % (10 * HASHS_PER_LINE))) but it would be nice if you could use 0x10 instead of 10 and masks here to avoid division. Or perhaps it doesn't matter. > + puts("\n"); > +} > + > +static void tcp_stream_on_closed(struct tcp_stream *tcp) > +{ > + if (tcp->status != TCP_ERR_OK) > + netcat_loop_state = NETLOOP_FAIL; > + > + /* > + * The status line will be shown after the download/upload > + * progress (see show_block_marker() function). This progress > + * generally have no final "\n", so jump to new line before > + * output the status > + */ > + 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); blank line before final return. Please fix globally > + 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; > +} > + > +/* > + * This function will be called on new connections (incoming or outgoing) > + * It MUST: > + * -- setup required tcp_stream callbacks (if connection will be accepted) > + * -- return a connection verdict: > + * 0: discard connection > + * 1: accept connection > + */ > +static int tcp_stream_on_create(struct tcp_stream *tcp) > +{ > + if (listen) { > + /* > + * We are listening for incoming connections. > + * Accept connections to netcat listen port only. > + */ > + if (tcp->lport != local_port) > + return 0; > + } else { > + /* > + * We are connecting to remote host. > + * Check remote IP:port to make sure that this is our connection > + */ > + 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) { !strchr Please don't compare against 0 or 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) { !tcp > + 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_save_start(void) > +{ > + reading = 0; > + return netcat_start(); > +} > -- > 2.45.2 > Regards, Simon
On 12.09.2024 03:59, Simon Glass wrote: > Hi Mikhail, > > On Mon, 9 Sept 2024 at 16:27, Mikhail Kshevetskiy > <mikhail.kshevetskiy@iopsys.eu> wrote: >> This patch adds downloading/uploading of data with netcat. >> Client/server mode both supported. >> >> How to test: >> ============ >> netcat-openbsd=1.219-1 from debian were used for a tests >> >> a) Load data from remote host. >> * U-Boot listen on tcp port 3456 >> * PC connects >> >> u-boot: netcat load ${loadaddr} 3456 >> PC: netcat -q1 ${UBOOT_IP} 3456 < image.itb >> >> b) Load data from remote host. >> * PC listen on tcp port 3456 >> * U-Boot connects >> >> PC: netcat -q1 -l -p 3456 < image.itb >> u-boot: netcat load ${loadaddr} ${PC_IP}:3456 >> >> c) Save data to remote host >> * U-Boot listen on tcp port 3456 >> * PC connects >> >> u-boot: netcat save ${loadaddr} ${data_size_in_hex} 3456 >> PC: netcat -w1 ${UBOOT_IP} 3456 >image.itb >> >> d) Save data to remote host >> * PC listen on tcp port 3456 >> * U-Boot connects >> >> PC: netcat -w1 -l -p 3456 >image.itb >> u-boot: netcat save ${loadaddr} ${data_size_in_hex} ${PC_IP}:3456 >> >> Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@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 | 181 +++++++++++++++++++++++++++++++++++++++++++ >> 7 files changed, 248 insertions(+), 6 deletions(-) >> create mode 100644 include/net/netcat.h >> create mode 100644 net/netcat.c > Reviewed-by: Simon Glass <sjg@chromium.org> Can/should I add this "Reviewed-by" to the next patch version? > > nits below > >> 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. > netcat-like > > Please add a reference to the protocol or the 'netcat' tool or both. > Help must be at least 3 lines. Netcat (https://en.wikipedia.org/wiki/Netcat) uses plain TCP/UDP for data delivery. In the TCP case, TCP by itself provides reliable, ordered, and error-checked data delivery, so no additional protocols are required. Is it enough to write the following description? netcat is a simple command to load/store kernel, or other files, using well-known netcat (nc) utility. Unlike classic netcat utility this command supports TCP-based data transfer only, thus no data will be lost or reordered. Any netcat implementation should work, but openbsd one was tested only. >> + >> config CMD_MII >> bool "mii" >> imply CMD_MDIO >> diff --git a/cmd/net.c b/cmd/net.c >> index 53ce2bc5d0c..364139ec5b9 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")) >> + return netboot_common(NETCAT_LOAD, cmdtp, argc - 1, argv + 1); >> + else if (!strcmp(argv[1], "save")) >> + return netboot_common(NETCAT_SAVE, cmdtp, argc - 1, argv + 1); >> + else >> + return 1; >> +} >> + > Needs longhelp Could you explain? Usage examples? > >> +U_BOOT_CMD( >> + netcat, 5, 1, do_netcat, >> + "load/store data via tcp netcat utility", >> + "load [loadAddress] [[hostIPaddr:]port]\n" >> + "save 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_SAVE)) >> 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_SAVE)) >> 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_SAVE)) { >> 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..0af6493788a 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_SAVE, 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..d8e09aaaa55 >> --- /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@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_save_start() - begin netcat in data saving mode >> + */ >> +void netcat_save_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..d81604a57ce 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> > That should be above net/tcp Is there any reasons? Should I move <net/wget.h> as well? > >> #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_SAVE: >> + netcat_save_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..633afe5c60b >> --- /dev/null >> +++ b/net/netcat.c >> @@ -0,0 +1,181 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * netcat support driver >> + * Copyright (C) 2024 IOPSYS Software Solutions AB >> + * Author: Mikhail Kshevetskiy <mikhail.kshevetskiy@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) > else if (!((packets + 1) % (10 * HASHS_PER_LINE))) > > but it would be nice if you could use 0x10 instead of 10 and masks > here to avoid division. Or perhaps it doesn't matter. >> + puts("\n"); >> +} >> + >> +static void tcp_stream_on_closed(struct tcp_stream *tcp) >> +{ >> + if (tcp->status != TCP_ERR_OK) >> + netcat_loop_state = NETLOOP_FAIL; >> + >> + /* >> + * The status line will be shown after the download/upload >> + * progress (see show_block_marker() function). This progress >> + * generally have no final "\n", so jump to new line before >> + * output the status >> + */ >> + 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); > blank line before final return. Please fix globally > >> + 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; >> +} >> + >> +/* >> + * This function will be called on new connections (incoming or outgoing) >> + * It MUST: >> + * -- setup required tcp_stream callbacks (if connection will be accepted) >> + * -- return a connection verdict: >> + * 0: discard connection >> + * 1: accept connection >> + */ >> +static int tcp_stream_on_create(struct tcp_stream *tcp) >> +{ >> + if (listen) { >> + /* >> + * We are listening for incoming connections. >> + * Accept connections to netcat listen port only. >> + */ >> + if (tcp->lport != local_port) >> + return 0; >> + } else { >> + /* >> + * We are connecting to remote host. >> + * Check remote IP:port to make sure that this is our connection >> + */ >> + 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) { > !strchr > > Please don't compare against 0 or 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) { > !tcp > >> + 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_save_start(void) >> +{ >> + reading = 0; >> + return netcat_start(); >> +} >> -- >> 2.45.2 >> > Regards, > Simon
Hi Mikhail, On Sun, 15 Sept 2024 at 09:06, Mikhail Kshevetskiy <mikhail.kshevetskiy@genexis.eu> wrote: > > > On 12.09.2024 03:59, Simon Glass wrote: > > Hi Mikhail, > > > > On Mon, 9 Sept 2024 at 16:27, Mikhail Kshevetskiy > > <mikhail.kshevetskiy@iopsys.eu> wrote: > >> This patch adds downloading/uploading of data with netcat. > >> Client/server mode both supported. > >> > >> How to test: > >> ============ > >> netcat-openbsd=1.219-1 from debian were used for a tests > >> > >> a) Load data from remote host. > >> * U-Boot listen on tcp port 3456 > >> * PC connects > >> > >> u-boot: netcat load ${loadaddr} 3456 > >> PC: netcat -q1 ${UBOOT_IP} 3456 < image.itb > >> > >> b) Load data from remote host. > >> * PC listen on tcp port 3456 > >> * U-Boot connects > >> > >> PC: netcat -q1 -l -p 3456 < image.itb > >> u-boot: netcat load ${loadaddr} ${PC_IP}:3456 > >> > >> c) Save data to remote host > >> * U-Boot listen on tcp port 3456 > >> * PC connects > >> > >> u-boot: netcat save ${loadaddr} ${data_size_in_hex} 3456 > >> PC: netcat -w1 ${UBOOT_IP} 3456 >image.itb > >> > >> d) Save data to remote host > >> * PC listen on tcp port 3456 > >> * U-Boot connects > >> > >> PC: netcat -w1 -l -p 3456 >image.itb > >> u-boot: netcat save ${loadaddr} ${data_size_in_hex} ${PC_IP}:3456 > >> > >> Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@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 | 181 +++++++++++++++++++++++++++++++++++++++++++ > >> 7 files changed, 248 insertions(+), 6 deletions(-) > >> create mode 100644 include/net/netcat.h > >> create mode 100644 net/netcat.c > > Reviewed-by: Simon Glass <sjg@chromium.org> > > Can/should I add this "Reviewed-by" to the next patch version? Yes > > > > > nits below > > > >> 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. > > netcat-like > > > > Please add a reference to the protocol or the 'netcat' tool or both. > > Help must be at least 3 lines. > > Netcat (https://en.wikipedia.org/wiki/Netcat) uses plain TCP/UDP for > data delivery. In the TCP case, TCP by itself provides reliable, > ordered, and error-checked data delivery, so no additional protocols are > required. > > Is it enough to write the following description? > > netcat is a simple command to load/store kernel, or other files, > using well-known netcat (nc) utility. Unlike classic netcat utility > this command supports TCP-based data transfer only, thus no data > will be lost or reordered. Any netcat implementation should work, > but openbsd one was tested only. Yes, thanks > > > >> + > >> config CMD_MII > >> bool "mii" > >> imply CMD_MDIO > >> diff --git a/cmd/net.c b/cmd/net.c > >> index 53ce2bc5d0c..364139ec5b9 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")) > >> + return netboot_common(NETCAT_LOAD, cmdtp, argc - 1, argv + 1); > >> + else if (!strcmp(argv[1], "save")) > >> + return netboot_common(NETCAT_SAVE, cmdtp, argc - 1, argv + 1); > >> + else > >> + return 1; > >> +} > >> + > > Needs longhelp > Could you explain? Usage examples? I just mean something like this: U_BOOT_LONGHELP(bootmeth, "list [-a] - list available bootmeths (-a all)\n" "bootmeth order [<bd> ...] - select bootmeth order / subset to use"); That example is from bootmeth.c > > > >> +U_BOOT_CMD( > >> + netcat, 5, 1, do_netcat, > >> + "load/store data via tcp netcat utility", > >> + "load [loadAddress] [[hostIPaddr:]port]\n" > >> + "save 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_SAVE)) > >> 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_SAVE)) > >> 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_SAVE)) { > >> 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..0af6493788a 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_SAVE, 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..d8e09aaaa55 > >> --- /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@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_save_start() - begin netcat in data saving mode > >> + */ > >> +void netcat_save_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..d81604a57ce 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> > > That should be above net/tcp > > Is there any reasons? > > Should I move <net/wget.h> as well? Oh, yes, net/xxx should be before test/xxx See here: https://docs.u-boot.org/en/latest/develop/codingstyle.html#include-files [..] Regards, Simon
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..364139ec5b9 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")) + return netboot_common(NETCAT_LOAD, cmdtp, argc - 1, argv + 1); + else if (!strcmp(argv[1], "save")) + return netboot_common(NETCAT_SAVE, 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" + "save 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_SAVE)) 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_SAVE)) 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_SAVE)) { 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..0af6493788a 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_SAVE, 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..d8e09aaaa55 --- /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@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_save_start() - begin netcat in data saving mode + */ +void netcat_save_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..d81604a57ce 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_SAVE: + netcat_save_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..633afe5c60b --- /dev/null +++ b/net/netcat.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * netcat support driver + * Copyright (C) 2024 IOPSYS Software Solutions AB + * Author: Mikhail Kshevetskiy <mikhail.kshevetskiy@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; + + /* + * The status line will be shown after the download/upload + * progress (see show_block_marker() function). This progress + * generally have no final "\n", so jump to new line before + * output the status + */ + 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; +} + +/* + * This function will be called on new connections (incoming or outgoing) + * It MUST: + * -- setup required tcp_stream callbacks (if connection will be accepted) + * -- return a connection verdict: + * 0: discard connection + * 1: accept connection + */ +static int tcp_stream_on_create(struct tcp_stream *tcp) +{ + if (listen) { + /* + * We are listening for incoming connections. + * Accept connections to netcat listen port only. + */ + if (tcp->lport != local_port) + return 0; + } else { + /* + * We are connecting to remote host. + * Check remote IP:port to make sure that this is our connection + */ + 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_save_start(void) +{ + reading = 0; + return netcat_start(); +}
This patch adds downloading/uploading of data with netcat. Client/server mode both supported. How to test: ============ netcat-openbsd=1.219-1 from debian were used for a tests a) Load data from remote host. * U-Boot listen on tcp port 3456 * PC connects u-boot: netcat load ${loadaddr} 3456 PC: netcat -q1 ${UBOOT_IP} 3456 < image.itb b) Load data from remote host. * PC listen on tcp port 3456 * U-Boot connects PC: netcat -q1 -l -p 3456 < image.itb u-boot: netcat load ${loadaddr} ${PC_IP}:3456 c) Save data to remote host * U-Boot listen on tcp port 3456 * PC connects u-boot: netcat save ${loadaddr} ${data_size_in_hex} 3456 PC: netcat -w1 ${UBOOT_IP} 3456 >image.itb d) Save data to remote host * PC listen on tcp port 3456 * U-Boot connects PC: netcat -w1 -l -p 3456 >image.itb u-boot: netcat save ${loadaddr} ${data_size_in_hex} ${PC_IP}:3456 Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@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 | 181 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 248 insertions(+), 6 deletions(-) create mode 100644 include/net/netcat.h create mode 100644 net/netcat.c