diff options
Diffstat (limited to 'net/lwip')
| -rw-r--r-- | net/lwip/Makefile | 2 | ||||
| -rw-r--r-- | net/lwip/dhcp.c | 4 | ||||
| -rw-r--r-- | net/lwip/dns.c | 4 | ||||
| -rw-r--r-- | net/lwip/net-lwip.c | 89 | ||||
| -rw-r--r-- | net/lwip/ping.c | 11 | ||||
| -rw-r--r-- | net/lwip/tftp.c | 77 | ||||
| -rw-r--r-- | net/lwip/wget.c | 119 |
7 files changed, 247 insertions, 59 deletions
diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 950c5316bb9..5df222589b8 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -1,6 +1,6 @@ ccflags-y += -I$(srctree)/lib/lwip/lwip/src/include -I$(srctree)/lib/lwip/u-boot -obj-$(CONFIG_$(SPL_)DM_ETH) += net-lwip.o +obj-$(CONFIG_$(PHASE_)DM_ETH) += net-lwip.o obj-$(CONFIG_CMD_DHCP) += dhcp.o obj-$(CONFIG_CMD_DNS) += dns.o obj-$(CONFIG_CMD_PING) += ping.o diff --git a/net/lwip/dhcp.c b/net/lwip/dhcp.c index 3b7e4700c6e..043d2ab6e94 100644 --- a/net/lwip/dhcp.c +++ b/net/lwip/dhcp.c @@ -3,6 +3,7 @@ #include <command.h> #include <console.h> +#include <env.h> #include <log.h> #include <dm/device.h> #include <linux/delay.h> @@ -115,7 +116,8 @@ int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) int ret; struct udevice *dev; - net_lwip_set_current(); + if (net_lwip_eth_start() < 0) + return CMD_RET_FAILURE; dev = eth_get_dev(); if (!dev) { diff --git a/net/lwip/dns.c b/net/lwip/dns.c index 149bdb784dc..6862869d9e3 100644 --- a/net/lwip/dns.c +++ b/net/lwip/dns.c @@ -3,6 +3,7 @@ #include <command.h> #include <console.h> +#include <env.h> #include <lwip/dns.h> #include <lwip/timeouts.h> #include <net.h> @@ -121,7 +122,8 @@ int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) if (argc == 3) var = argv[2]; - net_lwip_set_current(); + if (net_lwip_eth_start() < 0) + return CMD_RET_FAILURE; return dns_loop(eth_get_dev(), name, var); } diff --git a/net/lwip/net-lwip.c b/net/lwip/net-lwip.c index 6b7b696dbf0..abc52b32049 100644 --- a/net/lwip/net-lwip.c +++ b/net/lwip/net-lwip.c @@ -3,6 +3,7 @@ /* Copyright (C) 2024 Linaro Ltd. */ #include <command.h> +#include <env.h> #include <dm/device.h> #include <dm/uclass.h> #include <hexdump.h> @@ -14,6 +15,7 @@ #include <lwip/init.h> #include <lwip/prot/etharp.h> #include <net.h> +#include <timer.h> /* xx:xx:xx:xx:xx:xx\0 */ #define MAC_ADDR_STRLEN 18 @@ -21,6 +23,8 @@ #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) void (*push_packet)(void *, int len) = 0; #endif +static int net_try_count; +static int net_restarted; int net_restart_wrap; static uchar net_pkt_buf[(PKTBUFSRX) * PKTSIZE_ALIGN + PKTALIGN]; uchar *net_rx_packets[PKTBUFSRX]; @@ -134,18 +138,27 @@ static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip, return 0; } -/* Initialize the lwIP stack and the ethernet devices and set current device */ -void net_lwip_set_current(void) +/* + * Initialize the network stack if needed and start the current device if valid + */ +int net_lwip_eth_start(void) { - static bool init_done; - - if (!init_done) { - eth_init_rings(); - eth_init(); - lwip_init(); - init_done = true; + int ret; + + net_init(); + if (eth_is_on_demand_init()) { + eth_halt(); + eth_set_current(); + ret = eth_init(); + if (ret < 0) { + eth_halt(); + return ret; + } + } else { + eth_init_state_only(); } - eth_set_current(); + + return 0; } static struct netif *new_netif(struct udevice *udev, bool with_ip) @@ -224,11 +237,20 @@ void net_lwip_remove_netif(struct netif *netif) free(netif); } +/* + * Initialize the network buffers, an ethernet device, and the lwIP stack + * (once). + */ int net_init(void) { - eth_set_current(); + static bool init_done; - net_lwip_new_netif(eth_get_dev()); + if (!init_done) { + eth_init_rings(); + eth_init(); + lwip_init(); + init_done = true; + } return 0; } @@ -319,5 +341,48 @@ int net_loop(enum proto_t protocol) u32_t sys_now(void) { +#if CONFIG_IS_ENABLED(SANDBOX_TIMER) + return timer_early_get_count(); +#else return get_timer(0); +#endif +} + +int net_start_again(void) +{ + char *nretry; + int retry_forever = 0; + unsigned long retrycnt = 0; + + nretry = env_get("netretry"); + if (nretry) { + if (!strcmp(nretry, "yes")) + retry_forever = 1; + else if (!strcmp(nretry, "no")) + retrycnt = 0; + else if (!strcmp(nretry, "once")) + retrycnt = 1; + else + retrycnt = simple_strtoul(nretry, NULL, 0); + } else { + retrycnt = 0; + retry_forever = 0; + } + + if ((!retry_forever) && (net_try_count > retrycnt)) { + eth_halt(); + /* + * We don't provide a way for the protocol to return an error, + * but this is almost always the reason. + */ + return -ETIMEDOUT; + } + + net_try_count++; + + eth_halt(); +#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER) + eth_try_another(!net_restarted); +#endif + return eth_init(); } diff --git a/net/lwip/ping.c b/net/lwip/ping.c index c586a96806d..d8042ceecf9 100644 --- a/net/lwip/ping.c +++ b/net/lwip/ping.c @@ -168,10 +168,13 @@ int do_ping(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) if (!ipaddr_aton(argv[1], &addr)) return CMD_RET_USAGE; - net_lwip_set_current(); - - if (ping_loop(eth_get_dev(), &addr) < 0) - return CMD_RET_FAILURE; +restart: + if (net_lwip_eth_start() < 0 || ping_loop(eth_get_dev(), &addr) < 0) { + if (net_start_again() == 0) + goto restart; + else + return CMD_RET_FAILURE; + } return CMD_RET_SUCCESS; } diff --git a/net/lwip/tftp.c b/net/lwip/tftp.c index 123d66b5dba..b7eb486ef77 100644 --- a/net/lwip/tftp.c +++ b/net/lwip/tftp.c @@ -6,8 +6,10 @@ #include <display_options.h> #include <dm/device.h> #include <efi_loader.h> +#include <env.h> #include <image.h> #include <linux/delay.h> +#include <linux/kconfig.h> #include <lwip/apps/tftp_client.h> #include <lwip/timeouts.h> #include <mapmem.h> @@ -15,6 +17,8 @@ #include <time.h> #define PROGRESS_PRINT_STEP_BYTES (10 * 1024) +/* Max time to wait for first data packet from server */ +#define NO_RSP_TIMEOUT_MS 10000 enum done_state { NOT_DONE = 0, @@ -31,6 +35,47 @@ struct tftp_ctx { enum done_state done; }; +/** + * store_block() - copy received data + * + * This function is called by the receive callback to copy a block of data + * into its final location (ctx->daddr). Before doing so, it checks if the copy + * is allowed. + * + * @ctx: the context for the current transfer + * @src: the data received from the TCP stack + * @len: the length of the data + */ +static int store_block(struct tftp_ctx *ctx, void *src, u16_t len) +{ + ulong store_addr = ctx->daddr; + void *ptr; + + if (CONFIG_IS_ENABLED(LMB)) { + if (store_addr + len < store_addr || + lmb_read_check(store_addr, len)) { + puts("\nTFTP error: "); + puts("trying to overwrite reserved memory...\n"); + return -1; + } + } + + ptr = map_sysmem(store_addr, len); + memcpy(ptr, src, len); + unmap_sysmem(ptr); + + ctx->daddr += len; + ctx->size += len; + ctx->block_count++; + if (ctx->block_count % 10 == 0) { + putc('#'); + if (ctx->block_count % (65 * 10) == 0) + puts("\n\t "); + } + + return 0; +} + static void *tftp_open(const char *fname, const char *mode, u8_t is_write) { return NULL; @@ -71,17 +116,9 @@ static int tftp_write(void *handle, struct pbuf *p) struct tftp_ctx *ctx = handle; struct pbuf *q; - for (q = p; q; q = q->next) { - memcpy((void *)ctx->daddr, q->payload, q->len); - ctx->daddr += q->len; - ctx->size += q->len; - ctx->block_count++; - if (ctx->block_count % 10 == 0) { - putc('#'); - if (ctx->block_count % (65 * 10) == 0) - puts("\n\t "); - } - } + for (q = p; q; q = q->next) + if (store_block(ctx, q->payload, q->len) < 0) + return -1; return 0; } @@ -106,6 +143,17 @@ static const struct tftp_context tftp_context = { tftp_error }; +static void no_response(void *arg) +{ + struct tftp_ctx *ctx = (struct tftp_ctx *)arg; + + if (ctx->size) + return; + + printf("Timeout!\n"); + ctx->done = FAILURE; +} + static int tftp_loop(struct udevice *udev, ulong addr, char *fname, ip_addr_t srvip, uint16_t srvport) { @@ -150,6 +198,7 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname, return -1; } + sys_timeout(NO_RSP_TIMEOUT_MS, no_response, &ctx); while (!ctx.done) { net_lwip_rx(udev, netif); sys_check_timeouts(); @@ -159,6 +208,7 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname, break; } } + sys_untimeout(no_response, (void *)&ctx); tftp_cleanup(); @@ -280,7 +330,10 @@ int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) goto out; } - net_lwip_set_current(); + if (net_lwip_eth_start() < 0) { + ret = CMD_RET_FAILURE; + goto out; + } if (tftp_loop(eth_get_dev(), laddr, fname, srvip, port) < 0) ret = CMD_RET_FAILURE; diff --git a/net/lwip/wget.c b/net/lwip/wget.c index ec098148835..f4fd9718285 100644 --- a/net/lwip/wget.c +++ b/net/lwip/wget.c @@ -5,9 +5,12 @@ #include <console.h> #include <display_options.h> #include <efi_loader.h> +#include <env.h> #include <image.h> +#include <linux/kconfig.h> #include <lwip/apps/http_client.h> #include "lwip/altcp_tls.h" +#include <lwip/errno.h> #include <lwip/timeouts.h> #include <rng.h> #include <mapmem.h> @@ -201,11 +204,58 @@ static int parse_legacy_arg(char *arg, char *nurl, size_t rem) return 0; } +/** + * store_block() - copy received data + * + * This function is called by the receive callback to copy a block of data + * into its final location (ctx->daddr). Before doing so, it checks if the copy + * is allowed. + * + * @ctx: the context for the current transfer + * @src: the data received from the TCP stack + * @len: the length of the data + */ +static int store_block(struct wget_ctx *ctx, void *src, u16_t len) +{ + ulong store_addr = ctx->daddr; + uchar *ptr; + + /* Avoid overflow */ + if (wget_info->buffer_size && wget_info->buffer_size < ctx->size + len) + return -1; + + if (CONFIG_IS_ENABLED(LMB) && wget_info->set_bootdev) { + if (store_addr + len < store_addr || + lmb_read_check(store_addr, len)) { + if (!wget_info->silent) { + printf("\nwget error: "); + printf("trying to overwrite reserved memory\n"); + } + return -1; + } + } + + ptr = map_sysmem(store_addr, len); + memcpy(ptr, src, len); + unmap_sysmem(ptr); + + ctx->daddr += len; + ctx->size += len; + if (ctx->size - ctx->prevsize > PROGRESS_PRINT_STEP_BYTES) { + if (!wget_info->silent) + printf("#"); + ctx->prevsize = ctx->size; + } + + return 0; +} + static err_t httpc_recv_cb(void *arg, struct altcp_pcb *pcb, struct pbuf *pbuf, err_t err) { struct wget_ctx *ctx = arg; struct pbuf *buf; + err_t ret; if (!pbuf) return ERR_BUF; @@ -214,18 +264,17 @@ static err_t httpc_recv_cb(void *arg, struct altcp_pcb *pcb, struct pbuf *pbuf, ctx->start_time = get_timer(0); for (buf = pbuf; buf; buf = buf->next) { - memcpy((void *)ctx->daddr, buf->payload, buf->len); - ctx->daddr += buf->len; - ctx->size += buf->len; - if (ctx->size - ctx->prevsize > PROGRESS_PRINT_STEP_BYTES) { - printf("#"); - ctx->prevsize = ctx->size; + if (store_block(ctx, buf->payload, buf->len) < 0) { + altcp_abort(pcb); + ret = ERR_BUF; + goto out; } } - altcp_recved(pcb, pbuf->tot_len); + ret = ERR_OK; +out: pbuf_free(pbuf); - return ERR_OK; + return ret; } static void httpc_result_cb(void *arg, httpc_result_t httpc_result, @@ -255,11 +304,15 @@ static void httpc_result_cb(void *arg, httpc_result_t httpc_result, elapsed = get_timer(ctx->start_time); if (!elapsed) elapsed = 1; - if (rx_content_len > PROGRESS_PRINT_STEP_BYTES) - printf("\n"); - printf("%u bytes transferred in %lu ms (", rx_content_len, elapsed); - print_size(rx_content_len / elapsed * 1000, "/s)\n"); - printf("Bytes transferred = %lu (%lx hex)\n", ctx->size, ctx->size); + if (!wget_info->silent) { + if (rx_content_len > PROGRESS_PRINT_STEP_BYTES) + printf("\n"); + printf("%u bytes transferred in %lu ms (", rx_content_len, + elapsed); + print_size(rx_content_len / elapsed * 1000, "/s)\n"); + printf("Bytes transferred = %lu (%lx hex)\n", ctx->size, + ctx->size); + } if (wget_info->set_bootdev) efi_set_bootdev("Http", ctx->server_name, ctx->path, map_sysmem(ctx->saved_daddr, 0), rx_content_len); @@ -339,7 +392,8 @@ static int _set_cacert(const void *addr, size_t sz) mbedtls_x509_crt_init(&crt); ret = mbedtls_x509_crt_parse(&crt, cacert, cacert_size); if (ret) { - printf("Could not parse certificates (%d)\n", ret); + if (!wget_info->silent) + printf("Could not parse certificates (%d)\n", ret); free(cacert); cacert = NULL; cacert_size = 0; @@ -372,13 +426,14 @@ static int set_cacert(char * const saddr, char * const ssz) #endif #endif /* CONFIG_WGET_CACERT || CONFIG_WGET_BUILTIN_CACERT */ -static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) +int wget_do_request(ulong dst_addr, char *uri) { #if CONFIG_IS_ENABLED(WGET_HTTPS) altcp_allocator_t tls_allocator; #endif httpc_connection_t conn; httpc_state_t *state; + struct udevice *udev; struct netif *netif; struct wget_ctx ctx; char *path; @@ -394,6 +449,14 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) if (parse_url(uri, ctx.server_name, &ctx.port, &path, &is_https)) return CMD_RET_USAGE; + if (net_lwip_eth_start() < 0) + return CMD_RET_FAILURE; + + if (!wget_info) + wget_info = &default_wget_info; + + udev = eth_get_dev(); + netif = net_lwip_new_netif(udev); if (!netif) return -1; @@ -413,9 +476,10 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) if (cacert_auth_mode == AUTH_REQUIRED) { if (!ca || !ca_sz) { - printf("Error: cacert authentication mode is " - "'required' but no CA certificates " - "given\n"); + if (!wget_info->silent) + printf("Error: cacert authentication " + "mode is 'required' but no CA " + "certificates given\n"); return CMD_RET_FAILURE; } } else if (cacert_auth_mode == AUTH_NONE) { @@ -430,6 +494,10 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) */ } + if (!ca && !wget_info->silent) { + printf("WARNING: no CA certificates, "); + printf("HTTPS connections not authenticated\n"); + } tls_allocator.alloc = &altcp_tls_alloc; tls_allocator.arg = altcp_tls_create_config_client(ca, ca_sz, @@ -454,6 +522,8 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) return CMD_RET_FAILURE; } + errno = 0; + while (!ctx.done) { net_lwip_rx(udev, netif); sys_check_timeouts(); @@ -466,17 +536,10 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) if (ctx.done == SUCCESS) return 0; - return -1; -} - -int wget_do_request(ulong dst_addr, char *uri) -{ - net_lwip_set_current(); - - if (!wget_info) - wget_info = &default_wget_info; + if (errno == EPERM && !wget_info->silent) + printf("Certificate verification failed\n"); - return wget_loop(eth_get_dev(), dst_addr, uri); + return -1; } int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) |
