blob: 361817ace65fb228b5a286cdf0656f31d33c1181 [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
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080025static const char bootfile1[] = "GET ";
26static const char bootfile3[] = " HTTP/1.0\r\n\r\n";
27static const char http_eom[] = "\r\n\r\n";
28static const char http_ok[] = "200";
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080029static const char linefeed[] = "\r\n";
30static struct in_addr web_server_ip;
31static int our_port;
32static int wget_timeout_count;
33
34struct pkt_qd {
35 uchar *pkt;
36 unsigned int tcp_seq_num;
37 unsigned int len;
38};
39
40/*
41 * This is a control structure for out of order packets received.
42 * The actual packet bufers are in the kernel space, and are
43 * expected to be overwritten by the downloaded image.
44 */
Richard Weinbergerbf44cf42023-07-20 14:51:56 +020045#define PKTQ_SZ (PKTBUFSRX / 4)
46static struct pkt_qd pkt_q[PKTQ_SZ];
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080047static int pkt_q_idx;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080048static unsigned int packets;
49
50static unsigned int initial_data_seq_num;
Yasuharu Shibata07a00ef2024-04-14 19:46:07 +090051static unsigned int next_data_seq_num;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080052
53static enum wget_state current_wget_state;
54
55static char *image_url;
56static unsigned int wget_timeout = WGET_TIMEOUT;
57
58static enum net_loop_state wget_loop_state;
59
60/* Timeout retry parameters */
61static u8 retry_action; /* actions for TCP retry */
62static unsigned int retry_tcp_ack_num; /* TCP retry acknowledge number*/
63static unsigned int retry_tcp_seq_num; /* TCP retry sequence number */
64static int retry_len; /* TCP retry length */
65
66/**
67 * store_block() - store block in memory
68 * @src: source of data
69 * @offset: offset
70 * @len: length
71 */
72static inline int store_block(uchar *src, unsigned int offset, unsigned int len)
73{
Masahisa Kojima77b0ae32023-11-10 13:25:34 +090074 ulong store_addr = image_load_addr + offset;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080075 ulong newsize = offset + len;
76 uchar *ptr;
77
Sughosh Ganu0d733f02024-08-26 17:29:22 +053078 if (CONFIG_IS_ENABLED(LMB)) {
Masahisa Kojima77b0ae32023-11-10 13:25:34 +090079 if (store_addr < image_load_addr ||
Sughosh Ganu77728092024-09-16 20:50:25 +053080 lmb_read_check(store_addr, len)) {
Masahisa Kojima77b0ae32023-11-10 13:25:34 +090081 printf("\nwget error: ");
82 printf("trying to overwrite reserved memory...\n");
83 return -1;
84 }
85 }
86
87 ptr = map_sysmem(store_addr, len);
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +080088 memcpy(ptr, src, len);
89 unmap_sysmem(ptr);
90
91 if (net_boot_file_size < (offset + len))
92 net_boot_file_size = newsize;
93
94 return 0;
95}
96
97/**
98 * wget_send_stored() - wget response dispatcher
99 *
100 * WARNING, This, and only this, is the place in wget.c where
101 * SEQUENCE NUMBERS are swapped between incoming (RX)
102 * and outgoing (TX).
103 * Procedure wget_handler() is correct for RX traffic.
104 */
105static void wget_send_stored(void)
106{
107 u8 action = retry_action;
108 int len = retry_len;
Dmitrii Merkurev3acd0542023-04-12 19:49:29 +0100109 unsigned int tcp_ack_num = retry_tcp_seq_num + (len == 0 ? 1 : len);
110 unsigned int tcp_seq_num = retry_tcp_ack_num;
Marek Vasut22a95082023-12-13 22:11:13 +0100111 unsigned int server_port;
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800112 uchar *ptr, *offset;
113
Marek Vasut22a95082023-12-13 22:11:13 +0100114 server_port = env_get_ulong("httpdstp", 10, SERVER_PORT) & 0xffff;
115
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800116 switch (current_wget_state) {
117 case WGET_CLOSED:
118 debug_cond(DEBUG_WGET, "wget: send SYN\n");
119 current_wget_state = WGET_CONNECTING;
Marek Vasut22a95082023-12-13 22:11:13 +0100120 net_send_tcp_packet(0, server_port, our_port, action,
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800121 tcp_seq_num, tcp_ack_num);
122 packets = 0;
123 break;
124 case WGET_CONNECTING:
125 pkt_q_idx = 0;
Marek Vasut22a95082023-12-13 22:11:13 +0100126 net_send_tcp_packet(0, server_port, our_port, action,
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800127 tcp_seq_num, tcp_ack_num);
128
129 ptr = net_tx_packet + net_eth_hdr_size() +
130 IP_TCP_HDR_SIZE + TCP_TSOPT_SIZE + 2;
131 offset = ptr;
132
133 memcpy(offset, &bootfile1, strlen(bootfile1));
134 offset += strlen(bootfile1);
135
136 memcpy(offset, image_url, strlen(image_url));
137 offset += strlen(image_url);
138
139 memcpy(offset, &bootfile3, strlen(bootfile3));
140 offset += strlen(bootfile3);
Marek Vasut22a95082023-12-13 22:11:13 +0100141 net_send_tcp_packet((offset - ptr), server_port, our_port,
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800142 TCP_PUSH, tcp_seq_num, tcp_ack_num);
143 current_wget_state = WGET_CONNECTED;
144 break;
145 case WGET_CONNECTED:
146 case WGET_TRANSFERRING:
147 case WGET_TRANSFERRED:
Marek Vasut22a95082023-12-13 22:11:13 +0100148 net_send_tcp_packet(0, server_port, our_port, action,
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800149 tcp_seq_num, tcp_ack_num);
150 break;
151 }
152}
153
Dmitrii Merkurev3acd0542023-04-12 19:49:29 +0100154static void wget_send(u8 action, unsigned int tcp_seq_num,
155 unsigned int tcp_ack_num, int len)
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800156{
157 retry_action = action;
158 retry_tcp_ack_num = tcp_ack_num;
159 retry_tcp_seq_num = tcp_seq_num;
160 retry_len = len;
161
162 wget_send_stored();
163}
164
165void wget_fail(char *error_message, unsigned int tcp_seq_num,
166 unsigned int tcp_ack_num, u8 action)
167{
168 printf("wget: Transfer Fail - %s\n", error_message);
169 net_set_timeout_handler(0, NULL);
170 wget_send(action, tcp_seq_num, tcp_ack_num, 0);
171}
172
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800173/*
174 * Interfaces of U-BOOT
175 */
176static void wget_timeout_handler(void)
177{
178 if (++wget_timeout_count > WGET_RETRY_COUNT) {
179 puts("\nRetry count exceeded; starting again\n");
180 wget_send(TCP_RST, 0, 0, 0);
181 net_start_again();
182 } else {
183 puts("T ");
184 net_set_timeout_handler(wget_timeout +
185 WGET_TIMEOUT * wget_timeout_count,
186 wget_timeout_handler);
187 wget_send_stored();
188 }
189}
190
191#define PKT_QUEUE_OFFSET 0x20000
192#define PKT_QUEUE_PACKET_SIZE 0x800
193
194static void wget_connected(uchar *pkt, unsigned int tcp_seq_num,
Dmitrii Merkurev3acd0542023-04-12 19:49:29 +0100195 u8 action, unsigned int tcp_ack_num, unsigned int len)
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800196{
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800197 uchar *pkt_in_q;
198 char *pos;
199 int hlen, i;
200 uchar *ptr1;
201
202 pkt[len] = '\0';
203 pos = strstr((char *)pkt, http_eom);
204
205 if (!pos) {
206 debug_cond(DEBUG_WGET,
207 "wget: Connected, data before Header %p\n", pkt);
208 pkt_in_q = (void *)image_load_addr + PKT_QUEUE_OFFSET +
209 (pkt_q_idx * PKT_QUEUE_PACKET_SIZE);
210
Yasuharu Shibataafab2682024-08-14 21:41:06 +0900211 ptr1 = map_sysmem((ulong)pkt_in_q, len);
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800212 memcpy(ptr1, pkt, len);
213 unmap_sysmem(ptr1);
214
215 pkt_q[pkt_q_idx].pkt = pkt_in_q;
216 pkt_q[pkt_q_idx].tcp_seq_num = tcp_seq_num;
217 pkt_q[pkt_q_idx].len = len;
218 pkt_q_idx++;
Richard Weinbergerbf44cf42023-07-20 14:51:56 +0200219
220 if (pkt_q_idx >= PKTQ_SZ) {
221 printf("wget: Fatal error, queue overrun!\n");
222 net_set_state(NETLOOP_FAIL);
223
224 return;
225 }
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800226 } else {
227 debug_cond(DEBUG_WGET, "wget: Connected HTTP Header %p\n", pkt);
228 /* sizeof(http_eom) - 1 is the string length of (http_eom) */
229 hlen = pos - (char *)pkt + sizeof(http_eom) - 1;
230 pos = strstr((char *)pkt, linefeed);
231 if (pos > 0)
232 i = pos - (char *)pkt;
233 else
234 i = hlen;
235 printf("%.*s", i, pkt);
236
237 current_wget_state = WGET_TRANSFERRING;
238
Yasuharu Shibata07a00ef2024-04-14 19:46:07 +0900239 initial_data_seq_num = tcp_seq_num + hlen;
240 next_data_seq_num = tcp_seq_num + len;
241
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800242 if (strstr((char *)pkt, http_ok) == 0) {
243 debug_cond(DEBUG_WGET,
244 "wget: Connected Bad Xfer\n");
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800245 wget_loop_state = NETLOOP_FAIL;
246 wget_send(action, tcp_seq_num, tcp_ack_num, len);
247 } else {
248 debug_cond(DEBUG_WGET,
Heinrich Schuchardt6b3cefc2024-10-09 01:02:05 +0200249 "wget: Connected Pkt %p hlen %x\n",
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800250 pkt, hlen);
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800251
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800252 net_boot_file_size = 0;
253
Masahisa Kojima77b0ae32023-11-10 13:25:34 +0900254 if (len > hlen) {
255 if (store_block(pkt + hlen, 0, len - hlen) != 0) {
256 wget_loop_state = NETLOOP_FAIL;
257 wget_fail("wget: store error\n", tcp_seq_num, tcp_ack_num, action);
258 net_set_state(NETLOOP_FAIL);
259 return;
260 }
261 }
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800262
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800263 for (i = 0; i < pkt_q_idx; i++) {
Masahisa Kojima77b0ae32023-11-10 13:25:34 +0900264 int err;
265
Yasuharu Shibataafab2682024-08-14 21:41:06 +0900266 ptr1 = map_sysmem((ulong)pkt_q[i].pkt,
267 pkt_q[i].len);
Masahisa Kojima77b0ae32023-11-10 13:25:34 +0900268 err = store_block(ptr1,
269 pkt_q[i].tcp_seq_num -
270 initial_data_seq_num,
271 pkt_q[i].len);
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800272 unmap_sysmem(ptr1);
273 debug_cond(DEBUG_WGET,
Heinrich Schuchardt6b3cefc2024-10-09 01:02:05 +0200274 "wget: Conncted pkt Q %p len %x\n",
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800275 pkt_q[i].pkt, pkt_q[i].len);
Masahisa Kojima77b0ae32023-11-10 13:25:34 +0900276 if (err) {
277 wget_loop_state = NETLOOP_FAIL;
278 wget_fail("wget: store error\n", tcp_seq_num, tcp_ack_num, action);
279 net_set_state(NETLOOP_FAIL);
280 return;
281 }
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800282 }
283 }
284 }
285 wget_send(action, tcp_seq_num, tcp_ack_num, len);
286}
287
288/**
Dmitrii Merkurev3acd0542023-04-12 19:49:29 +0100289 * wget_handler() - TCP handler of wget
290 * @pkt: pointer to the application packet
291 * @dport: destination TCP port
292 * @sip: source IP address
293 * @sport: source TCP port
294 * @tcp_seq_num: TCP sequential number
295 * @tcp_ack_num: TCP acknowledgment number
296 * @action: TCP action (SYN, ACK, FIN, etc)
297 * @len: packet length
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800298 *
299 * In the "application push" invocation, the TCP header with all
300 * its information is pointed to by the packet pointer.
301 */
Dmitrii Merkurev3acd0542023-04-12 19:49:29 +0100302static void wget_handler(uchar *pkt, u16 dport,
303 struct in_addr sip, u16 sport,
304 u32 tcp_seq_num, u32 tcp_ack_num,
305 u8 action, unsigned int len)
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800306{
307 enum tcp_state wget_tcp_state = tcp_get_tcp_state();
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800308
309 net_set_timeout_handler(wget_timeout, wget_timeout_handler);
310 packets++;
311
312 switch (current_wget_state) {
313 case WGET_CLOSED:
314 debug_cond(DEBUG_WGET, "wget: Handler: Error!, State wrong\n");
315 break;
316 case WGET_CONNECTING:
317 debug_cond(DEBUG_WGET,
Dmitrii Merkurev3acd0542023-04-12 19:49:29 +0100318 "wget: Connecting In len=%x, Seq=%u, Ack=%u\n",
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800319 len, tcp_seq_num, tcp_ack_num);
320 if (!len) {
321 if (wget_tcp_state == TCP_ESTABLISHED) {
322 debug_cond(DEBUG_WGET,
323 "wget: Cting, send, len=%x\n", len);
324 wget_send(action, tcp_seq_num, tcp_ack_num,
325 len);
326 } else {
327 printf("%.*s", len, pkt);
328 wget_fail("wget: Handler Connected Fail\n",
329 tcp_seq_num, tcp_ack_num, action);
330 }
331 }
332 break;
333 case WGET_CONNECTED:
Dmitrii Merkurev3acd0542023-04-12 19:49:29 +0100334 debug_cond(DEBUG_WGET, "wget: Connected seq=%u, len=%x\n",
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800335 tcp_seq_num, len);
336 if (!len) {
337 wget_fail("Image not found, no data returned\n",
338 tcp_seq_num, tcp_ack_num, action);
339 } else {
Dmitrii Merkurev3acd0542023-04-12 19:49:29 +0100340 wget_connected(pkt, tcp_seq_num, action, tcp_ack_num, len);
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800341 }
342 break;
343 case WGET_TRANSFERRING:
344 debug_cond(DEBUG_WGET,
345 "wget: Transferring, seq=%x, ack=%x,len=%x\n",
346 tcp_seq_num, tcp_ack_num, len);
347
Yasuharu Shibata07a00ef2024-04-14 19:46:07 +0900348 if (next_data_seq_num != tcp_seq_num) {
349 debug_cond(DEBUG_WGET, "wget: seq=%x packet was lost\n", next_data_seq_num);
350 return;
351 }
352 next_data_seq_num = tcp_seq_num + len;
353
Yasuharu Shibata2c9b5af2024-04-16 09:26:24 +0900354 if (store_block(pkt, tcp_seq_num - initial_data_seq_num, len) != 0) {
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800355 wget_fail("wget: store error\n",
356 tcp_seq_num, tcp_ack_num, action);
Masahisa Kojima77b0ae32023-11-10 13:25:34 +0900357 net_set_state(NETLOOP_FAIL);
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800358 return;
359 }
360
361 switch (wget_tcp_state) {
362 case TCP_FIN_WAIT_2:
363 wget_send(TCP_ACK, tcp_seq_num, tcp_ack_num, len);
364 fallthrough;
365 case TCP_SYN_SENT:
Dmitrii Merkurev3acd0542023-04-12 19:49:29 +0100366 case TCP_SYN_RECEIVED:
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800367 case TCP_CLOSING:
368 case TCP_FIN_WAIT_1:
369 case TCP_CLOSED:
370 net_set_state(NETLOOP_FAIL);
371 break;
372 case TCP_ESTABLISHED:
373 wget_send(TCP_ACK, tcp_seq_num, tcp_ack_num,
374 len);
375 wget_loop_state = NETLOOP_SUCCESS;
376 break;
377 case TCP_CLOSE_WAIT: /* End of transfer */
378 current_wget_state = WGET_TRANSFERRED;
379 wget_send(action | TCP_ACK | TCP_FIN,
380 tcp_seq_num, tcp_ack_num, len);
381 break;
382 }
383 break;
384 case WGET_TRANSFERRED:
385 printf("Packets received %d, Transfer Successful\n", packets);
386 net_set_state(wget_loop_state);
Jerome Forissier612b2b12024-09-11 11:58:22 +0200387 efi_set_bootdev("Net", "", image_url,
388 map_sysmem(image_load_addr, 0),
389 net_boot_file_size);
Heinrich Schuchardtdf1d94b2024-10-09 13:08:54 +0200390 env_set_hex("filesize", net_boot_file_size);
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800391 break;
392 }
393}
394
395#define RANDOM_PORT_START 1024
396#define RANDOM_PORT_RANGE 0x4000
397
398/**
399 * random_port() - make port a little random (1024-17407)
400 *
401 * Return: random port number from 1024 to 17407
402 *
403 * This keeps the math somewhat trivial to compute, and seems to work with
404 * all supported protocols/clients/servers
405 */
406static unsigned int random_port(void)
407{
408 return RANDOM_PORT_START + (get_timer(0) % RANDOM_PORT_RANGE);
409}
410
411#define BLOCKSIZE 512
412
413void wget_start(void)
414{
415 image_url = strchr(net_boot_file_name, ':');
416 if (image_url > 0) {
417 web_server_ip = string_to_ip(net_boot_file_name);
418 ++image_url;
419 net_server_ip = web_server_ip;
420 } else {
421 web_server_ip = net_server_ip;
422 image_url = net_boot_file_name;
423 }
424
425 debug_cond(DEBUG_WGET,
426 "wget: Transfer HTTP Server %pI4; our IP %pI4\n",
427 &web_server_ip, &net_ip);
428
429 /* Check if we need to send across this subnet */
430 if (net_gateway.s_addr && net_netmask.s_addr) {
431 struct in_addr our_net;
432 struct in_addr server_net;
433
434 our_net.s_addr = net_ip.s_addr & net_netmask.s_addr;
435 server_net.s_addr = net_server_ip.s_addr & net_netmask.s_addr;
436 if (our_net.s_addr != server_net.s_addr)
437 debug_cond(DEBUG_WGET,
438 "wget: sending through gateway %pI4",
439 &net_gateway);
440 }
441 debug_cond(DEBUG_WGET, "URL '%s'\n", image_url);
442
443 if (net_boot_file_expected_size_in_blocks) {
444 debug_cond(DEBUG_WGET, "wget: Size is 0x%x Bytes = ",
445 net_boot_file_expected_size_in_blocks * BLOCKSIZE);
446 print_size(net_boot_file_expected_size_in_blocks * BLOCKSIZE,
447 "");
448 }
449 debug_cond(DEBUG_WGET,
450 "\nwget:Load address: 0x%lx\nLoading: *\b", image_load_addr);
451
Ying-Chun Liu (PaulLiu)cc96a1d2022-11-08 14:17:29 +0800452 net_set_timeout_handler(wget_timeout, wget_timeout_handler);
453 tcp_set_tcp_handler(wget_handler);
454
455 wget_timeout_count = 0;
456 current_wget_state = WGET_CLOSED;
457
458 our_port = random_port();
459
460 /*
461 * Zero out server ether to force arp resolution in case
462 * the server ip for the previous u-boot command, for example dns
463 * is not the same as the web server ip.
464 */
465
466 memset(net_server_ethaddr, 0, 6);
467
468 wget_send(TCP_SYN, 0, 0, 0);
469}
Masahisa Kojima6721d182023-11-10 13:25:35 +0900470
471#if (IS_ENABLED(CONFIG_CMD_DNS))
472int wget_with_dns(ulong dst_addr, char *uri)
473{
474 int ret;
475 char *s, *host_name, *file_name, *str_copy;
476
477 /*
478 * Download file using wget.
479 *
480 * U-Boot wget takes the target uri in this format.
481 * "<http server ip>:<file path>" e.g.) 192.168.1.1:/sample/test.iso
482 * Need to resolve the http server ip address before starting wget.
483 */
484 str_copy = strdup(uri);
485 if (!str_copy)
486 return -ENOMEM;
487
488 s = str_copy + strlen("http://");
489 host_name = strsep(&s, "/");
490 if (!s) {
491 log_err("Error: invalied uri, no file path\n");
492 ret = -EINVAL;
493 goto out;
494 }
495 file_name = s;
496
497 /* TODO: If the given uri has ip address for the http server, skip dns */
498 net_dns_resolve = host_name;
499 net_dns_env_var = "httpserverip";
500 if (net_loop(DNS) < 0) {
501 log_err("Error: dns lookup of %s failed, check setup\n", net_dns_resolve);
502 ret = -EINVAL;
503 goto out;
504 }
505 s = env_get("httpserverip");
506 if (!s) {
507 ret = -EINVAL;
508 goto out;
509 }
510
511 strlcpy(net_boot_file_name, s, sizeof(net_boot_file_name));
512 strlcat(net_boot_file_name, ":/", sizeof(net_boot_file_name)); /* append '/' which is removed by strsep() */
513 strlcat(net_boot_file_name, file_name, sizeof(net_boot_file_name));
514 image_load_addr = dst_addr;
515 ret = net_loop(WGET);
516
517out:
518 free(str_copy);
519
520 return ret;
521}
522#endif
Masahisa Kojimae501ce12023-11-10 13:25:41 +0900523
524/**
525 * wget_validate_uri() - validate the uri for wget
526 *
527 * @uri: uri string
528 *
529 * This function follows the current U-Boot wget implementation.
530 * scheme: only "http:" is supported
531 * authority:
532 * - user information: not supported
533 * - host: supported
534 * - port: not supported(always use the default port)
535 *
536 * Uri is expected to be correctly percent encoded.
537 * This is the minimum check, control codes(0x1-0x19, 0x7F, except '\0')
538 * and space character(0x20) are not allowed.
539 *
540 * TODO: stricter uri conformance check
541 *
542 * Return: true on success, false on failure
543 */
544bool wget_validate_uri(char *uri)
545{
546 char c;
547 bool ret = true;
548 char *str_copy, *s, *authority;
549
550 for (c = 0x1; c < 0x21; c++) {
551 if (strchr(uri, c)) {
552 log_err("invalid character is used\n");
553 return false;
554 }
555 }
556 if (strchr(uri, 0x7f)) {
557 log_err("invalid character is used\n");
558 return false;
559 }
560
561 if (strncmp(uri, "http://", 7)) {
562 log_err("only http:// is supported\n");
563 return false;
564 }
565 str_copy = strdup(uri);
566 if (!str_copy)
567 return false;
568
569 s = str_copy + strlen("http://");
570 authority = strsep(&s, "/");
571 if (!s) {
572 log_err("invalid uri, no file path\n");
573 ret = false;
574 goto out;
575 }
576 s = strchr(authority, '@');
577 if (s) {
578 log_err("user information is not supported\n");
579 ret = false;
580 goto out;
581 }
582 s = strchr(authority, ':');
583 if (s) {
584 log_err("user defined port is not supported\n");
585 ret = false;
586 goto out;
587 }
588
589out:
590 free(str_copy);
591
592 return ret;
593}