diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/Kconfig | 9 | ||||
-rw-r--r-- | net/Makefile | 2 | ||||
-rw-r--r-- | net/lwip/Makefile | 2 | ||||
-rw-r--r-- | net/lwip/wget.c | 60 | ||||
-rw-r--r-- | net/net-common.c | 14 | ||||
-rw-r--r-- | net/net.c | 11 | ||||
-rw-r--r-- | net/wget.c | 123 |
7 files changed, 174 insertions, 47 deletions
diff --git a/net/Kconfig b/net/Kconfig index 76ab7d91eeb..b4bb68dd613 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -244,6 +244,15 @@ config NET_RANDOM_ETHADDR generated. It will be saved to the appropriate environment variable, too. +config WGET + bool "Enable wget" + select PROT_TCP if NET + select PROT_TCP_LWIP if NET_LWIP + select PROT_DNS_LWIP if NET_LWIP + help + Selecting this will enable wget, an interface to send HTTP requests + via the network stack. + config TFTP_BLOCKSIZE int "TFTP block size" default 1468 diff --git a/net/Makefile b/net/Makefile index 209377aeb26..7c917b318c0 100644 --- a/net/Makefile +++ b/net/Makefile @@ -29,7 +29,7 @@ obj-$(CONFIG_$(PHASE_)TCP_FUNCTION_FASTBOOT) += fastboot_tcp.o 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_WGET) += wget.o # Disable this warning as it is triggered by: # sprintf(buf, index ? "foo%d" : "foo", index) diff --git a/net/lwip/Makefile b/net/lwip/Makefile index f2558f8763a..79dd6b3fb50 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -5,4 +5,4 @@ obj-$(CONFIG_CMD_DHCP) += dhcp.o obj-$(CONFIG_CMD_DNS) += dns.o obj-$(CONFIG_CMD_PING) += ping.o obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o -obj-$(CONFIG_CMD_WGET) += wget.o +obj-$(CONFIG_WGET) += wget.o diff --git a/net/lwip/wget.c b/net/lwip/wget.c index 5501ffdd004..b76f6c0f1d9 100644 --- a/net/lwip/wget.c +++ b/net/lwip/wget.c @@ -27,6 +27,8 @@ enum done_state { }; struct wget_ctx { + char server_name[SERVER_NAME_SIZE]; + u16 port; char *path; ulong daddr; ulong saved_daddr; @@ -36,6 +38,23 @@ struct wget_ctx { enum done_state done; }; +static void wget_lwip_fill_info(struct pbuf *hdr, u16_t hdr_len, u32_t hdr_cont_len) +{ + if (wget_info->headers) { + if (hdr_len < MAX_HTTP_HEADERS_SIZE) + pbuf_copy_partial(hdr, (void *)wget_info->headers, hdr_len, 0); + else + hdr_len = 0; + wget_info->headers[hdr_len] = 0; + } + wget_info->hdr_cont_len = (u32)hdr_cont_len; +} + +static void wget_lwip_set_file_size(u32_t rx_content_len) +{ + wget_info->file_size = (ulong)rx_content_len; +} + bool wget_validate_uri(char *uri); int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, @@ -215,6 +234,13 @@ static void httpc_result_cb(void *arg, httpc_result_t httpc_result, struct wget_ctx *ctx = arg; ulong elapsed; + wget_info->status_code = (u32)srv_res; + + if (err == ERR_BUF) { + ctx->done = FAILURE; + return; + } + if (httpc_result != HTTPC_RESULT_OK) { log_err("\nHTTP client error %d\n", httpc_result); ctx->done = FAILURE; @@ -234,8 +260,10 @@ static void httpc_result_cb(void *arg, httpc_result_t httpc_result, 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); - efi_set_bootdev("Net", "", ctx->path, map_sysmem(ctx->saved_daddr, 0), - rx_content_len); + if (wget_info->set_bootdev) + efi_set_bootdev("Http", ctx->server_name, ctx->path, map_sysmem(ctx->saved_daddr, 0), + rx_content_len); + wget_lwip_set_file_size(rx_content_len); if (env_set_hex("filesize", rx_content_len) || env_set_hex("fileaddr", ctx->saved_daddr)) { log_err("Could not set filesize or fileaddr\n"); @@ -246,9 +274,19 @@ static void httpc_result_cb(void *arg, httpc_result_t httpc_result, ctx->done = SUCCESS; } +static err_t httpc_headers_done_cb(httpc_state_t *connection, void *arg, struct pbuf *hdr, + u16_t hdr_len, u32_t content_len) +{ + wget_lwip_fill_info(hdr, hdr_len, content_len); + + if (wget_info->check_buffer_size && (ulong)content_len > wget_info->buffer_size) + return ERR_BUF; + + return ERR_OK; +} + static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) { - char server_name[SERVER_NAME_SIZE]; #if defined CONFIG_WGET_HTTPS altcp_allocator_t tls_allocator; #endif @@ -257,7 +295,6 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) struct netif *netif; struct wget_ctx ctx; char *path; - u16 port; bool is_https; ctx.daddr = dst_addr; @@ -267,7 +304,7 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) ctx.prevsize = 0; ctx.start_time = 0; - if (parse_url(uri, server_name, &port, &path, &is_https)) + if (parse_url(uri, ctx.server_name, &ctx.port, &path, &is_https)) return CMD_RET_USAGE; netif = net_lwip_new_netif(udev); @@ -279,7 +316,7 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) if (is_https) { tls_allocator.alloc = &altcp_tls_alloc; tls_allocator.arg = - altcp_tls_create_config_client(NULL, 0, server_name); + altcp_tls_create_config_client(NULL, 0, ctx.server_name); if (!tls_allocator.arg) { log_err("error: Cannot create a TLS connection\n"); @@ -292,8 +329,9 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) #endif conn.result_fn = httpc_result_cb; + conn.headers_done_fn = httpc_headers_done_cb; ctx.path = path; - if (httpc_get_file_dns(server_name, port, path, &conn, httpc_recv_cb, + if (httpc_get_file_dns(ctx.server_name, ctx.port, path, &conn, httpc_recv_cb, &ctx, &state)) { net_lwip_remove_netif(netif); return CMD_RET_FAILURE; @@ -314,10 +352,13 @@ static int wget_loop(struct udevice *udev, ulong dst_addr, char *uri) return -1; } -int wget_with_dns(ulong dst_addr, char *uri) +int wget_do_request(ulong dst_addr, char *uri) { eth_set_current(); + if (!wget_info) + wget_info = &default_wget_info; + return wget_loop(eth_get_dev(), dst_addr, uri); } @@ -344,7 +385,8 @@ int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) if (parse_legacy_arg(url, nurl, sizeof(nurl))) return CMD_RET_FAILURE; - if (wget_with_dns(dst_addr, nurl)) + wget_info = &default_wget_info; + if (wget_do_request(dst_addr, nurl)) return CMD_RET_FAILURE; return CMD_RET_SUCCESS; diff --git a/net/net-common.c b/net/net-common.c index a7f767d5e9c..e01b0da7d7b 100644 --- a/net/net-common.c +++ b/net/net-common.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#include <net-common.h> void copy_filename(char *dst, const char *src, int size) { @@ -11,3 +12,16 @@ void copy_filename(char *dst, const char *src, int size) *dst++ = *src++; *dst = '\0'; } + +struct wget_http_info default_wget_info = { + .method = WGET_HTTP_METHOD_GET, + .set_bootdev = true, +}; + +struct wget_http_info *wget_info; + +int wget_request(ulong dst_addr, char *uri, struct wget_http_info *info) +{ + wget_info = info ? info : &default_wget_info; + return wget_do_request(dst_addr, uri); +} diff --git a/net/net.c b/net/net.c index f47e9fbe33a..ca35704f661 100644 --- a/net/net.c +++ b/net/net.c @@ -1723,17 +1723,6 @@ int net_parse_bootfile(struct in_addr *ipaddr, char *filename, int max_len) return 1; } -void ip_to_string(struct in_addr x, char *s) -{ - x.s_addr = ntohl(x.s_addr); - sprintf(s, "%d.%d.%d.%d", - (int) ((x.s_addr >> 24) & 0xff), - (int) ((x.s_addr >> 16) & 0xff), - (int) ((x.s_addr >> 8) & 0xff), - (int) ((x.s_addr >> 0) & 0xff) - ); -} - void vlan_to_string(ushort x, char *s) { x = ntohs(x); diff --git a/net/wget.c b/net/wget.c index 361817ace65..d338eaf4ef3 100644 --- a/net/wget.c +++ b/net/wget.c @@ -22,10 +22,11 @@ DECLARE_GLOBAL_DATA_PTR; /* The default, change with environment variable 'httpdstp' */ #define SERVER_PORT 80 -static const char bootfile1[] = "GET "; +static const char bootfileGET[] = "GET "; +static const char bootfileHEAD[] = "HEAD "; static const char bootfile3[] = " HTTP/1.0\r\n\r\n"; static const char http_eom[] = "\r\n\r\n"; -static const char http_ok[] = "200"; +static const char content_len[] = "Content-Length"; static const char linefeed[] = "\r\n"; static struct in_addr web_server_ip; static int our_port; @@ -45,6 +46,7 @@ struct pkt_qd { #define PKTQ_SZ (PKTBUFSRX / 4) static struct pkt_qd pkt_q[PKTQ_SZ]; static int pkt_q_idx; +static unsigned long content_length; static unsigned int packets; static unsigned int initial_data_seq_num; @@ -75,7 +77,7 @@ static inline int store_block(uchar *src, unsigned int offset, unsigned int len) ulong newsize = offset + len; uchar *ptr; - if (CONFIG_IS_ENABLED(LMB)) { + if (CONFIG_IS_ENABLED(LMB) && wget_info->set_bootdev) { if (store_addr < image_load_addr || lmb_read_check(store_addr, len)) { printf("\nwget error: "); @@ -130,8 +132,17 @@ static void wget_send_stored(void) IP_TCP_HDR_SIZE + TCP_TSOPT_SIZE + 2; offset = ptr; - memcpy(offset, &bootfile1, strlen(bootfile1)); - offset += strlen(bootfile1); + switch (wget_info->method) { + case WGET_HTTP_METHOD_HEAD: + memcpy(offset, &bootfileHEAD, strlen(bootfileHEAD)); + offset += strlen(bootfileHEAD); + break; + case WGET_HTTP_METHOD_GET: + default: + memcpy(offset, &bootfileGET, strlen(bootfileGET)); + offset += strlen(bootfileGET); + break; + } memcpy(offset, image_url, strlen(image_url)); offset += strlen(image_url); @@ -191,6 +202,52 @@ static void wget_timeout_handler(void) #define PKT_QUEUE_OFFSET 0x20000 #define PKT_QUEUE_PACKET_SIZE 0x800 +static void wget_fill_info(const uchar *pkt, int hlen) +{ + const char *first_space; + const char *second_space; + char *pos, *end; + + if (wget_info->headers) { + if (hlen < MAX_HTTP_HEADERS_SIZE) + strncpy(wget_info->headers, pkt, hlen); + else + hlen = 0; + wget_info->headers[hlen] = 0; + } + + //Get status code + first_space = strchr(pkt, ' '); + if (!first_space) { + wget_info->status_code = -1; + return; + } + + second_space = strchr(first_space + 1, ' '); + if (!second_space) { + wget_info->status_code = -1; + return; + } + + wget_info->status_code = (u32)simple_strtoul(first_space + 1, &end, 10); + + if (second_space != end) + wget_info->status_code = -1; + + pos = strstr((char *)pkt, content_len); + + if (pos) { + pos += sizeof(content_len) + 1; + while (*pos == ' ') + pos++; + content_length = simple_strtoul(pos, &end, 10); + debug_cond(DEBUG_WGET, + "wget: Connected Len %lu\n", + content_length); + wget_info->hdr_cont_len = content_length; + } +} + static void wget_connected(uchar *pkt, unsigned int tcp_seq_num, u8 action, unsigned int tcp_ack_num, unsigned int len) { @@ -239,7 +296,11 @@ static void wget_connected(uchar *pkt, unsigned int tcp_seq_num, initial_data_seq_num = tcp_seq_num + hlen; next_data_seq_num = tcp_seq_num + len; - if (strstr((char *)pkt, http_ok) == 0) { + wget_fill_info(pkt, hlen); + debug_cond(DEBUG_WGET, + "wget: HTTP Status Code %d\n", wget_info->status_code); + + if (wget_info->status_code != 200) { debug_cond(DEBUG_WGET, "wget: Connected Bad Xfer\n"); wget_loop_state = NETLOOP_FAIL; @@ -384,10 +445,13 @@ static void wget_handler(uchar *pkt, u16 dport, case WGET_TRANSFERRED: printf("Packets received %d, Transfer Successful\n", packets); net_set_state(wget_loop_state); - efi_set_bootdev("Net", "", image_url, - map_sysmem(image_load_addr, 0), - net_boot_file_size); - env_set_hex("filesize", net_boot_file_size); + wget_info->file_size = net_boot_file_size; + if (wget_info->method == WGET_HTTP_METHOD_GET && wget_info->set_bootdev) { + efi_set_bootdev("Http", NULL, image_url, + map_sysmem(image_load_addr, 0), + net_boot_file_size); + env_set_hex("filesize", net_boot_file_size); + } break; } } @@ -412,6 +476,9 @@ static unsigned int random_port(void) void wget_start(void) { + if (!wget_info) + wget_info = &default_wget_info; + image_url = strchr(net_boot_file_name, ':'); if (image_url > 0) { web_server_ip = string_to_ip(net_boot_file_name); @@ -468,8 +535,7 @@ void wget_start(void) wget_send(TCP_SYN, 0, 0, 0); } -#if (IS_ENABLED(CONFIG_CMD_DNS)) -int wget_with_dns(ulong dst_addr, char *uri) +int wget_do_request(ulong dst_addr, char *uri) { int ret; char *s, *host_name, *file_name, *str_copy; @@ -488,24 +554,32 @@ int wget_with_dns(ulong dst_addr, char *uri) s = str_copy + strlen("http://"); host_name = strsep(&s, "/"); if (!s) { - log_err("Error: invalied uri, no file path\n"); ret = -EINVAL; goto out; } file_name = s; - /* TODO: If the given uri has ip address for the http server, skip dns */ - net_dns_resolve = host_name; - net_dns_env_var = "httpserverip"; - if (net_loop(DNS) < 0) { - log_err("Error: dns lookup of %s failed, check setup\n", net_dns_resolve); - ret = -EINVAL; - goto out; - } - s = env_get("httpserverip"); - if (!s) { + host_name = strsep(&host_name, ":"); + + if (string_to_ip(host_name).s_addr) { + s = host_name; + } else { +#if IS_ENABLED(CONFIG_CMD_DNS) + net_dns_resolve = host_name; + net_dns_env_var = "httpserverip"; + if (net_loop(DNS) < 0) { + ret = -EINVAL; + goto out; + } + s = env_get("httpserverip"); + if (!s) { + ret = -EINVAL; + goto out; + } +#else ret = -EINVAL; goto out; +#endif } strlcpy(net_boot_file_name, s, sizeof(net_boot_file_name)); @@ -517,9 +591,8 @@ int wget_with_dns(ulong dst_addr, char *uri) out: free(str_copy); - return ret; + return ret < 0 ? ret : 0; } -#endif /** * wget_validate_uri() - validate the uri for wget |