blob: 3c0fff488ebaa4fab6ea79aa63db011a9dc9f976 [file] [log] [blame]
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * WGET/HTTP support driver based on U-BOOT's nfs.c
4 * Copyright Duncan Hare <dh@synoia.com> 2017
5 */
6
Masahisa Kojima77b0ae32023-11-10 13:25:34 +09007#include <asm/global_data.h>
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +08008#include <command.h>
Michael Wallecaad55b2022-12-28 16:27:14 +01009#include <display_options.h>
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080010#include <env.h>
Jerome Forissier612b2b12024-09-11 11:58:22 +020011#include <efi_loader.h>
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080012#include <image.h>
Masahisa Kojima77b0ae32023-11-10 13:25:34 +090013#include <lmb.h>
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080014#include <mapmem.h>
15#include <net.h>
16#include <net/tcp.h>
17#include <net/wget.h>
Masahisa Kojima6721d182023-11-10 13:25:35 +090018#include <stdlib.h>
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080019
Masahisa Kojima77b0ae32023-11-10 13:25:34 +090020DECLARE_GLOBAL_DATA_PTR;
21
Marek Vasut22a95082023-12-13 22:11:13 +010022/* The default, change with environment variable 'httpdstp' */
23#define SERVER_PORT 80
24
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030025#define HASHES_PER_LINE 65
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080026
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030027#define HTTP_MAX_HDR_LEN 2048
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080028
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030029#define HTTP_STATUS_BAD 0
30#define HTTP_STATUS_OK 200
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080031
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030032static const char http_proto[] = "HTTP/1.0";
33static const char http_eom[] = "\r\n\r\n";
34static const char content_len[] = "Content-Length:";
35static const char linefeed[] = "\r\n";
36static struct in_addr web_server_ip;
37static unsigned int server_port;
38static unsigned long content_length;
39static u32 http_hdr_size, max_rx_pos;
40static int wget_tsize_num_hash;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080041
42static char *image_url;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080043static enum net_loop_state wget_loop_state;
44
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080045/**
46 * store_block() - store block in memory
47 * @src: source of data
48 * @offset: offset
49 * @len: length
50 */
51static inline int store_block(uchar *src, unsigned int offset, unsigned int len)
52{
Masahisa Kojima77b0ae32023-11-10 13:25:34 +090053 ulong store_addr = image_load_addr + offset;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080054 uchar *ptr;
55
Adriano Cordova3f3409c2025-02-06 14:40:11 -030056 // Avoid overflow
57 if (wget_info->buffer_size && wget_info->buffer_size < offset + len)
58 return -1;
Adriano Cordova47f35e32024-11-11 18:08:58 -030059 if (CONFIG_IS_ENABLED(LMB) && wget_info->set_bootdev) {
Masahisa Kojima77b0ae32023-11-10 13:25:34 +090060 if (store_addr < image_load_addr ||
Sughosh Ganu77728092024-09-16 20:50:25 +053061 lmb_read_check(store_addr, len)) {
Jerome Forissier95b10352025-04-17 15:26:58 +020062 if (!wget_info->silent) {
63 printf("\nwget error: ");
64 printf("trying to overwrite reserved memory\n");
65 }
Masahisa Kojima77b0ae32023-11-10 13:25:34 +090066 return -1;
67 }
68 }
69
70 ptr = map_sysmem(store_addr, len);
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080071 memcpy(ptr, src, len);
72 unmap_sysmem(ptr);
73
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080074 return 0;
75}
76
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030077static void show_block_marker(u32 packets)
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080078{
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030079 int cnt;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080080
Jerome Forissier95b10352025-04-17 15:26:58 +020081 if (wget_info->silent)
82 return;
83
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030084 if (content_length != -1) {
85 if (net_boot_file_size > content_length)
86 content_length = net_boot_file_size;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080087
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030088 cnt = net_boot_file_size * 50 / content_length;
89 while (wget_tsize_num_hash < cnt) {
90 putc('#');
91 wget_tsize_num_hash++;
Adriano Cordova47f35e32024-11-11 18:08:58 -030092 }
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +030093 } else {
94 if ((packets % 10) == 0)
95 putc('#');
96 else if (((packets + 1) % (10 * HASHES_PER_LINE)) == 0)
97 puts("\n");
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080098 }
99}
100
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300101static void tcp_stream_on_closed(struct tcp_stream *tcp)
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800102{
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300103 if (tcp->status != TCP_ERR_OK)
104 wget_loop_state = NETLOOP_FAIL;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800105
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300106 net_set_state(wget_loop_state);
107 if (wget_loop_state != NETLOOP_SUCCESS) {
108 net_boot_file_size = 0;
Jerome Forissier95b10352025-04-17 15:26:58 +0200109 if (!wget_info->silent)
110 printf("\nwget: Transfer Fail, TCP status - %d\n",
111 tcp->status);
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300112 return;
113 }
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800114
Jerome Forissier95b10352025-04-17 15:26:58 +0200115 if (!wget_info->silent)
116 printf("\nPackets received %d, Transfer Successful\n",
117 tcp->rx_packets);
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300118 wget_info->file_size = net_boot_file_size;
119 if (wget_info->method == WGET_HTTP_METHOD_GET && wget_info->set_bootdev) {
120 efi_set_bootdev("Http", NULL, image_url,
121 map_sysmem(image_load_addr, 0),
122 net_boot_file_size);
123 env_set_hex("filesize", net_boot_file_size);
124 }
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800125}
126
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300127static void tcp_stream_on_rcv_nxt_update(struct tcp_stream *tcp, u32 rx_bytes)
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800128{
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300129 char *pos, *tail;
130 uchar saved, *ptr;
131 int reply_len;
132
133 if (http_hdr_size) {
134 net_boot_file_size = rx_bytes - http_hdr_size;
135 show_block_marker(tcp->rx_packets);
136 return;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800137 }
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800138
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300139 ptr = map_sysmem(image_load_addr, rx_bytes + 1);
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800140
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300141 saved = ptr[rx_bytes];
142 ptr[rx_bytes] = '\0';
143 pos = strstr((char *)ptr, http_eom);
144 ptr[rx_bytes] = saved;
145
146 if (!pos) {
147 if (rx_bytes < HTTP_MAX_HDR_LEN &&
148 tcp->state == TCP_ESTABLISHED)
149 goto end;
Adriano Cordova47f35e32024-11-11 18:08:58 -0300150
Jerome Forissier95b10352025-04-17 15:26:58 +0200151 if (!wget_info->silent)
152 printf("ERROR: misssed HTTP header\n");
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300153 tcp_stream_close(tcp);
154 goto end;
Heinrich Schuchardt89e40902024-11-26 13:19:20 -0300155 }
Adriano Cordova47f35e32024-11-11 18:08:58 -0300156
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300157 http_hdr_size = pos - (char *)ptr + strlen(http_eom);
158 *pos = '\0';
159
160 if (wget_info->headers && http_hdr_size < MAX_HTTP_HEADERS_SIZE)
161 strcpy(wget_info->headers, ptr);
162
163 /* check for HTTP proto */
164 if (strncasecmp((char *)ptr, "HTTP/", 5)) {
165 debug_cond(DEBUG_WGET, "wget: Connected Bad Xfer "
166 "(no HTTP Status Line found)\n");
167 tcp_stream_close(tcp);
168 goto end;
Adriano Cordova47f35e32024-11-11 18:08:58 -0300169 }
170
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300171 /* get HTTP reply len */
172 pos = strstr((char *)ptr, linefeed);
173 if (pos)
174 reply_len = pos - (char *)ptr;
175 else
176 reply_len = http_hdr_size - strlen(http_eom);
177
178 pos = strchr((char *)ptr, ' ');
179 if (!pos || pos - (char *)ptr > reply_len) {
180 debug_cond(DEBUG_WGET, "wget: Connected Bad Xfer "
181 "(no HTTP Status Code found)\n");
182 tcp_stream_close(tcp);
183 goto end;
Adriano Cordova47f35e32024-11-11 18:08:58 -0300184 }
185
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300186 wget_info->status_code = (u32)simple_strtoul(pos + 1, &tail, 10);
187 if (tail == pos + 1 || *tail != ' ') {
188 debug_cond(DEBUG_WGET, "wget: Connected Bad Xfer "
189 "(bad HTTP Status Code)\n");
190 tcp_stream_close(tcp);
191 goto end;
192 }
Adriano Cordova47f35e32024-11-11 18:08:58 -0300193
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300194 debug_cond(DEBUG_WGET,
195 "wget: HTTP Status Code %d\n", wget_info->status_code);
Adriano Cordova47f35e32024-11-11 18:08:58 -0300196
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300197 if (wget_info->status_code != HTTP_STATUS_OK) {
198 debug_cond(DEBUG_WGET, "wget: Connected Bad Xfer\n");
199 tcp_stream_close(tcp);
200 goto end;
201 }
Adriano Cordova47f35e32024-11-11 18:08:58 -0300202
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300203 debug_cond(DEBUG_WGET, "wget: Connctd pkt %p hlen %x\n",
204 ptr, http_hdr_size);
205
206 content_length = -1;
207 pos = strstr((char *)ptr, content_len);
Adriano Cordova47f35e32024-11-11 18:08:58 -0300208 if (pos) {
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300209 pos += strlen(content_len) + 1;
Adriano Cordova47f35e32024-11-11 18:08:58 -0300210 while (*pos == ' ')
211 pos++;
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300212 content_length = simple_strtoul(pos, &tail, 10);
213 if (*tail != '\r' && *tail != '\n' && *tail != '\0')
214 content_length = -1;
215 }
216
217 if (content_length >= 0) {
Adriano Cordova47f35e32024-11-11 18:08:58 -0300218 debug_cond(DEBUG_WGET,
219 "wget: Connected Len %lu\n",
220 content_length);
221 wget_info->hdr_cont_len = content_length;
Adriano Cordova3f3409c2025-02-06 14:40:11 -0300222 if (wget_info->buffer_size && wget_info->buffer_size < wget_info->hdr_cont_len){
223 tcp_stream_reset(tcp);
224 goto end;
225 }
226
Adriano Cordova47f35e32024-11-11 18:08:58 -0300227 }
Adriano Cordova47f35e32024-11-11 18:08:58 -0300228
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300229 net_boot_file_size = rx_bytes - http_hdr_size;
230 memmove(ptr, ptr + http_hdr_size, max_rx_pos + 1 - http_hdr_size);
231 wget_loop_state = NETLOOP_SUCCESS;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800232
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300233end:
234 unmap_sysmem(ptr);
235}
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800236
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300237static int tcp_stream_rx(struct tcp_stream *tcp, u32 rx_offs, void *buf, int len)
238{
239 if ((max_rx_pos == (u32)(-1)) || (max_rx_pos < rx_offs + len - 1))
240 max_rx_pos = rx_offs + len - 1;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800241
Adriano Cordova3f3409c2025-02-06 14:40:11 -0300242 // Avoid overflow
243 if (store_block(buf, rx_offs - http_hdr_size, len) < 0)
244 return -1;
Masahisa Kojima77b0ae32023-11-10 13:25:34 +0900245
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300246 return len;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800247}
248
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300249static int tcp_stream_tx(struct tcp_stream *tcp, u32 tx_offs, void *buf, int maxlen)
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800250{
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300251 int ret;
252 const char *method;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800253
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300254 if (tx_offs)
255 return 0;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800256
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300257 switch (wget_info->method) {
258 case WGET_HTTP_METHOD_HEAD:
259 method = "HEAD";
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800260 break;
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300261 case WGET_HTTP_METHOD_GET:
262 default:
263 method = "GET";
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800264 break;
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300265 }
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800266
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300267 ret = snprintf(buf, maxlen, "%s %s %s\r\n\r\n",
268 method, image_url, http_proto);
Yasuharu Shibata07a00ef2024-04-14 19:46:07 +0900269
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300270 return ret;
271}
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800272
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300273static int tcp_stream_on_create(struct tcp_stream *tcp)
274{
275 if (tcp->rhost.s_addr != web_server_ip.s_addr ||
276 tcp->rport != server_port)
277 return 0;
278
279 tcp->max_retry_count = WGET_RETRY_COUNT;
280 tcp->initial_timeout = WGET_TIMEOUT;
281 tcp->on_closed = tcp_stream_on_closed;
282 tcp->on_rcv_nxt_update = tcp_stream_on_rcv_nxt_update;
283 tcp->rx = tcp_stream_rx;
284 tcp->tx = tcp_stream_tx;
285
286 return 1;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800287}
288
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800289#define BLOCKSIZE 512
290
291void wget_start(void)
292{
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300293 struct tcp_stream *tcp;
Mikhail Kshevetskiy215f73f2024-12-28 13:46:30 +0300294
Adriano Cordova47f35e32024-11-11 18:08:58 -0300295 if (!wget_info)
296 wget_info = &default_wget_info;
297
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800298 image_url = strchr(net_boot_file_name, ':');
299 if (image_url > 0) {
300 web_server_ip = string_to_ip(net_boot_file_name);
301 ++image_url;
302 net_server_ip = web_server_ip;
303 } else {
304 web_server_ip = net_server_ip;
305 image_url = net_boot_file_name;
306 }
307
308 debug_cond(DEBUG_WGET,
309 "wget: Transfer HTTP Server %pI4; our IP %pI4\n",
310 &web_server_ip, &net_ip);
311
312 /* Check if we need to send across this subnet */
313 if (net_gateway.s_addr && net_netmask.s_addr) {
314 struct in_addr our_net;
315 struct in_addr server_net;
316
317 our_net.s_addr = net_ip.s_addr & net_netmask.s_addr;
318 server_net.s_addr = net_server_ip.s_addr & net_netmask.s_addr;
319 if (our_net.s_addr != server_net.s_addr)
320 debug_cond(DEBUG_WGET,
321 "wget: sending through gateway %pI4",
322 &net_gateway);
323 }
324 debug_cond(DEBUG_WGET, "URL '%s'\n", image_url);
325
326 if (net_boot_file_expected_size_in_blocks) {
327 debug_cond(DEBUG_WGET, "wget: Size is 0x%x Bytes = ",
328 net_boot_file_expected_size_in_blocks * BLOCKSIZE);
329 print_size(net_boot_file_expected_size_in_blocks * BLOCKSIZE,
330 "");
331 }
332 debug_cond(DEBUG_WGET,
333 "\nwget:Load address: 0x%lx\nLoading: *\b", image_load_addr);
334
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800335 /*
336 * Zero out server ether to force arp resolution in case
337 * the server ip for the previous u-boot command, for example dns
338 * is not the same as the web server ip.
339 */
340
341 memset(net_server_ethaddr, 0, 6);
342
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300343 max_rx_pos = (u32)(-1);
344 net_boot_file_size = 0;
345 http_hdr_size = 0;
346 wget_tsize_num_hash = 0;
347 wget_loop_state = NETLOOP_FAIL;
348
349 wget_info->status_code = HTTP_STATUS_BAD;
350 wget_info->file_size = 0;
351 wget_info->hdr_cont_len = 0;
352 if (wget_info->headers)
353 wget_info->headers[0] = 0;
354
Mikhail Kshevetskiy215f73f2024-12-28 13:46:30 +0300355 server_port = env_get_ulong("httpdstp", 10, SERVER_PORT) & 0xffff;
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300356 tcp_stream_set_on_create_handler(tcp_stream_on_create);
Mikhail Kshevetskiy215f73f2024-12-28 13:46:30 +0300357 tcp = tcp_stream_connect(web_server_ip, server_port);
358 if (!tcp) {
Jerome Forissier95b10352025-04-17 15:26:58 +0200359 if (!wget_info->silent)
360 printf("No free tcp streams\n");
Mikhail Kshevetskiy215f73f2024-12-28 13:46:30 +0300361 net_set_state(NETLOOP_FAIL);
362 return;
363 }
Mikhail Kshevetskiye2c4e9d2024-12-28 13:46:32 +0300364 tcp_stream_put(tcp);
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800365}
Masahisa Kojima6721d182023-11-10 13:25:35 +0900366
Adriano Cordovab479fc42024-12-04 00:05:16 -0300367int wget_do_request(ulong dst_addr, char *uri)
Masahisa Kojima6721d182023-11-10 13:25:35 +0900368{
369 int ret;
370 char *s, *host_name, *file_name, *str_copy;
371
372 /*
373 * Download file using wget.
374 *
375 * U-Boot wget takes the target uri in this format.
376 * "<http server ip>:<file path>" e.g.) 192.168.1.1:/sample/test.iso
377 * Need to resolve the http server ip address before starting wget.
378 */
379 str_copy = strdup(uri);
380 if (!str_copy)
381 return -ENOMEM;
382
383 s = str_copy + strlen("http://");
384 host_name = strsep(&s, "/");
385 if (!s) {
Masahisa Kojima6721d182023-11-10 13:25:35 +0900386 ret = -EINVAL;
387 goto out;
388 }
389 file_name = s;
390
Adriano Cordovab479fc42024-12-04 00:05:16 -0300391 host_name = strsep(&host_name, ":");
392
393 if (string_to_ip(host_name).s_addr) {
394 s = host_name;
395 } else {
396#if IS_ENABLED(CONFIG_CMD_DNS)
397 net_dns_resolve = host_name;
398 net_dns_env_var = "httpserverip";
399 if (net_loop(DNS) < 0) {
400 ret = -EINVAL;
401 goto out;
402 }
403 s = env_get("httpserverip");
404 if (!s) {
405 ret = -EINVAL;
406 goto out;
407 }
408#else
Masahisa Kojima6721d182023-11-10 13:25:35 +0900409 ret = -EINVAL;
410 goto out;
Adriano Cordovab479fc42024-12-04 00:05:16 -0300411#endif
Masahisa Kojima6721d182023-11-10 13:25:35 +0900412 }
413
414 strlcpy(net_boot_file_name, s, sizeof(net_boot_file_name));
415 strlcat(net_boot_file_name, ":/", sizeof(net_boot_file_name)); /* append '/' which is removed by strsep() */
416 strlcat(net_boot_file_name, file_name, sizeof(net_boot_file_name));
417 image_load_addr = dst_addr;
418 ret = net_loop(WGET);
419
420out:
421 free(str_copy);
422
Adriano Cordova450b2342024-11-11 18:08:59 -0300423 return ret < 0 ? ret : 0;
Masahisa Kojima6721d182023-11-10 13:25:35 +0900424}
Masahisa Kojimae501ce12023-11-10 13:25:41 +0900425
426/**
427 * wget_validate_uri() - validate the uri for wget
428 *
429 * @uri: uri string
430 *
431 * This function follows the current U-Boot wget implementation.
432 * scheme: only "http:" is supported
433 * authority:
434 * - user information: not supported
435 * - host: supported
436 * - port: not supported(always use the default port)
437 *
438 * Uri is expected to be correctly percent encoded.
439 * This is the minimum check, control codes(0x1-0x19, 0x7F, except '\0')
440 * and space character(0x20) are not allowed.
441 *
442 * TODO: stricter uri conformance check
443 *
444 * Return: true on success, false on failure
445 */
446bool wget_validate_uri(char *uri)
447{
448 char c;
449 bool ret = true;
450 char *str_copy, *s, *authority;
451
452 for (c = 0x1; c < 0x21; c++) {
453 if (strchr(uri, c)) {
454 log_err("invalid character is used\n");
455 return false;
456 }
457 }
458 if (strchr(uri, 0x7f)) {
459 log_err("invalid character is used\n");
460 return false;
461 }
462
463 if (strncmp(uri, "http://", 7)) {
464 log_err("only http:// is supported\n");
465 return false;
466 }
467 str_copy = strdup(uri);
468 if (!str_copy)
469 return false;
470
471 s = str_copy + strlen("http://");
472 authority = strsep(&s, "/");
473 if (!s) {
474 log_err("invalid uri, no file path\n");
475 ret = false;
476 goto out;
477 }
478 s = strchr(authority, '@');
479 if (s) {
480 log_err("user information is not supported\n");
481 ret = false;
482 goto out;
483 }
484 s = strchr(authority, ':');
485 if (s) {
486 log_err("user defined port is not supported\n");
487 ret = false;
488 goto out;
489 }
490
491out:
492 free(str_copy);
493
494 return ret;
495}