blob: f1dd7abeff69a75510f650f646ea71c932177b83 [file] [log] [blame]
Ying-Chun Liu (PaulLiu)cfbae482022-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 Kojima04592ad2023-11-10 13:25:34 +09007#include <asm/global_data.h>
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +08008#include <command.h>
Michael Wallefe1489b2022-12-28 16:27:14 +01009#include <display_options.h>
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +080010#include <env.h>
11#include <image.h>
Masahisa Kojima04592ad2023-11-10 13:25:34 +090012#include <lmb.h>
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +080013#include <mapmem.h>
14#include <net.h>
15#include <net/tcp.h>
16#include <net/wget.h>
Masahisa Kojima8cf18da2023-11-10 13:25:35 +090017#include <stdlib.h>
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +080018
Masahisa Kojima04592ad2023-11-10 13:25:34 +090019DECLARE_GLOBAL_DATA_PTR;
20
Marek Vasut4caacb22023-12-13 22:11:13 +010021/* The default, change with environment variable 'httpdstp' */
22#define SERVER_PORT 80
23
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +080024static const char bootfile1[] = "GET ";
25static const char bootfile3[] = " HTTP/1.0\r\n\r\n";
26static const char http_eom[] = "\r\n\r\n";
27static const char http_ok[] = "200";
28static const char content_len[] = "Content-Length";
29static 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 Weinbergera8bd5ec2023-07-20 14:51:56 +020045#define PKTQ_SZ (PKTBUFSRX / 4)
46static struct pkt_qd pkt_q[PKTQ_SZ];
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +080047static int pkt_q_idx;
48static unsigned long content_length;
49static unsigned int packets;
50
51static unsigned int initial_data_seq_num;
Yasuharu Shibatacab78672024-04-14 19:46:07 +090052static unsigned int next_data_seq_num;
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +080053
54static enum wget_state current_wget_state;
55
56static char *image_url;
57static unsigned int wget_timeout = WGET_TIMEOUT;
58
59static enum net_loop_state wget_loop_state;
60
61/* Timeout retry parameters */
62static u8 retry_action; /* actions for TCP retry */
63static unsigned int retry_tcp_ack_num; /* TCP retry acknowledge number*/
64static unsigned int retry_tcp_seq_num; /* TCP retry sequence number */
65static int retry_len; /* TCP retry length */
66
Masahisa Kojima04592ad2023-11-10 13:25:34 +090067static ulong wget_load_size;
68
69/**
70 * wget_init_max_size() - initialize maximum load size
71 *
72 * Return: 0 if success, -1 if fails
73 */
74static int wget_init_load_size(void)
75{
76 struct lmb lmb;
77 phys_size_t max_size;
78
79 lmb_init_and_reserve(&lmb, gd->bd, (void *)gd->fdt_blob);
80
81 max_size = lmb_get_free_size(&lmb, image_load_addr);
82 if (!max_size)
83 return -1;
84
85 wget_load_size = max_size;
86
87 return 0;
88}
89
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +080090/**
91 * store_block() - store block in memory
92 * @src: source of data
93 * @offset: offset
94 * @len: length
95 */
96static inline int store_block(uchar *src, unsigned int offset, unsigned int len)
97{
Masahisa Kojima04592ad2023-11-10 13:25:34 +090098 ulong store_addr = image_load_addr + offset;
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +080099 ulong newsize = offset + len;
100 uchar *ptr;
101
Masahisa Kojima04592ad2023-11-10 13:25:34 +0900102 if (IS_ENABLED(CONFIG_LMB)) {
103 ulong end_addr = image_load_addr + wget_load_size;
104
105 if (!end_addr)
106 end_addr = ULONG_MAX;
107
108 if (store_addr < image_load_addr ||
109 store_addr + len > end_addr) {
110 printf("\nwget error: ");
111 printf("trying to overwrite reserved memory...\n");
112 return -1;
113 }
114 }
115
116 ptr = map_sysmem(store_addr, len);
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800117 memcpy(ptr, src, len);
118 unmap_sysmem(ptr);
119
120 if (net_boot_file_size < (offset + len))
121 net_boot_file_size = newsize;
122
123 return 0;
124}
125
126/**
127 * wget_send_stored() - wget response dispatcher
128 *
129 * WARNING, This, and only this, is the place in wget.c where
130 * SEQUENCE NUMBERS are swapped between incoming (RX)
131 * and outgoing (TX).
132 * Procedure wget_handler() is correct for RX traffic.
133 */
134static void wget_send_stored(void)
135{
136 u8 action = retry_action;
137 int len = retry_len;
Dmitrii Merkurev08fb8da2023-04-12 19:49:29 +0100138 unsigned int tcp_ack_num = retry_tcp_seq_num + (len == 0 ? 1 : len);
139 unsigned int tcp_seq_num = retry_tcp_ack_num;
Marek Vasut4caacb22023-12-13 22:11:13 +0100140 unsigned int server_port;
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800141 uchar *ptr, *offset;
142
Marek Vasut4caacb22023-12-13 22:11:13 +0100143 server_port = env_get_ulong("httpdstp", 10, SERVER_PORT) & 0xffff;
144
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800145 switch (current_wget_state) {
146 case WGET_CLOSED:
147 debug_cond(DEBUG_WGET, "wget: send SYN\n");
148 current_wget_state = WGET_CONNECTING;
Marek Vasut4caacb22023-12-13 22:11:13 +0100149 net_send_tcp_packet(0, server_port, our_port, action,
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800150 tcp_seq_num, tcp_ack_num);
151 packets = 0;
152 break;
153 case WGET_CONNECTING:
154 pkt_q_idx = 0;
Marek Vasut4caacb22023-12-13 22:11:13 +0100155 net_send_tcp_packet(0, server_port, our_port, action,
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800156 tcp_seq_num, tcp_ack_num);
157
158 ptr = net_tx_packet + net_eth_hdr_size() +
159 IP_TCP_HDR_SIZE + TCP_TSOPT_SIZE + 2;
160 offset = ptr;
161
162 memcpy(offset, &bootfile1, strlen(bootfile1));
163 offset += strlen(bootfile1);
164
165 memcpy(offset, image_url, strlen(image_url));
166 offset += strlen(image_url);
167
168 memcpy(offset, &bootfile3, strlen(bootfile3));
169 offset += strlen(bootfile3);
Marek Vasut4caacb22023-12-13 22:11:13 +0100170 net_send_tcp_packet((offset - ptr), server_port, our_port,
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800171 TCP_PUSH, tcp_seq_num, tcp_ack_num);
172 current_wget_state = WGET_CONNECTED;
173 break;
174 case WGET_CONNECTED:
175 case WGET_TRANSFERRING:
176 case WGET_TRANSFERRED:
Marek Vasut4caacb22023-12-13 22:11:13 +0100177 net_send_tcp_packet(0, server_port, our_port, action,
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800178 tcp_seq_num, tcp_ack_num);
179 break;
180 }
181}
182
Dmitrii Merkurev08fb8da2023-04-12 19:49:29 +0100183static void wget_send(u8 action, unsigned int tcp_seq_num,
184 unsigned int tcp_ack_num, int len)
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800185{
186 retry_action = action;
187 retry_tcp_ack_num = tcp_ack_num;
188 retry_tcp_seq_num = tcp_seq_num;
189 retry_len = len;
190
191 wget_send_stored();
192}
193
194void wget_fail(char *error_message, unsigned int tcp_seq_num,
195 unsigned int tcp_ack_num, u8 action)
196{
197 printf("wget: Transfer Fail - %s\n", error_message);
198 net_set_timeout_handler(0, NULL);
199 wget_send(action, tcp_seq_num, tcp_ack_num, 0);
200}
201
202void wget_success(u8 action, unsigned int tcp_seq_num,
203 unsigned int tcp_ack_num, int len, int packets)
204{
205 printf("Packets received %d, Transfer Successful\n", packets);
206 wget_send(action, tcp_seq_num, tcp_ack_num, len);
207}
208
209/*
210 * Interfaces of U-BOOT
211 */
212static void wget_timeout_handler(void)
213{
214 if (++wget_timeout_count > WGET_RETRY_COUNT) {
215 puts("\nRetry count exceeded; starting again\n");
216 wget_send(TCP_RST, 0, 0, 0);
217 net_start_again();
218 } else {
219 puts("T ");
220 net_set_timeout_handler(wget_timeout +
221 WGET_TIMEOUT * wget_timeout_count,
222 wget_timeout_handler);
223 wget_send_stored();
224 }
225}
226
227#define PKT_QUEUE_OFFSET 0x20000
228#define PKT_QUEUE_PACKET_SIZE 0x800
229
230static void wget_connected(uchar *pkt, unsigned int tcp_seq_num,
Dmitrii Merkurev08fb8da2023-04-12 19:49:29 +0100231 u8 action, unsigned int tcp_ack_num, unsigned int len)
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800232{
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800233 uchar *pkt_in_q;
234 char *pos;
235 int hlen, i;
236 uchar *ptr1;
237
238 pkt[len] = '\0';
239 pos = strstr((char *)pkt, http_eom);
240
241 if (!pos) {
242 debug_cond(DEBUG_WGET,
243 "wget: Connected, data before Header %p\n", pkt);
244 pkt_in_q = (void *)image_load_addr + PKT_QUEUE_OFFSET +
245 (pkt_q_idx * PKT_QUEUE_PACKET_SIZE);
246
247 ptr1 = map_sysmem((phys_addr_t)pkt_in_q, len);
248 memcpy(ptr1, pkt, len);
249 unmap_sysmem(ptr1);
250
251 pkt_q[pkt_q_idx].pkt = pkt_in_q;
252 pkt_q[pkt_q_idx].tcp_seq_num = tcp_seq_num;
253 pkt_q[pkt_q_idx].len = len;
254 pkt_q_idx++;
Richard Weinbergera8bd5ec2023-07-20 14:51:56 +0200255
256 if (pkt_q_idx >= PKTQ_SZ) {
257 printf("wget: Fatal error, queue overrun!\n");
258 net_set_state(NETLOOP_FAIL);
259
260 return;
261 }
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800262 } else {
263 debug_cond(DEBUG_WGET, "wget: Connected HTTP Header %p\n", pkt);
264 /* sizeof(http_eom) - 1 is the string length of (http_eom) */
265 hlen = pos - (char *)pkt + sizeof(http_eom) - 1;
266 pos = strstr((char *)pkt, linefeed);
267 if (pos > 0)
268 i = pos - (char *)pkt;
269 else
270 i = hlen;
271 printf("%.*s", i, pkt);
272
273 current_wget_state = WGET_TRANSFERRING;
274
Yasuharu Shibatacab78672024-04-14 19:46:07 +0900275 initial_data_seq_num = tcp_seq_num + hlen;
276 next_data_seq_num = tcp_seq_num + len;
277
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800278 if (strstr((char *)pkt, http_ok) == 0) {
279 debug_cond(DEBUG_WGET,
280 "wget: Connected Bad Xfer\n");
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800281 wget_loop_state = NETLOOP_FAIL;
282 wget_send(action, tcp_seq_num, tcp_ack_num, len);
283 } else {
284 debug_cond(DEBUG_WGET,
285 "wget: Connctd pkt %p hlen %x\n",
286 pkt, hlen);
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800287
288 pos = strstr((char *)pkt, content_len);
289 if (!pos) {
290 content_length = -1;
291 } else {
292 pos += sizeof(content_len) + 2;
293 strict_strtoul(pos, 10, &content_length);
294 debug_cond(DEBUG_WGET,
295 "wget: Connected Len %lu\n",
296 content_length);
297 }
298
299 net_boot_file_size = 0;
300
Masahisa Kojima04592ad2023-11-10 13:25:34 +0900301 if (len > hlen) {
302 if (store_block(pkt + hlen, 0, len - hlen) != 0) {
303 wget_loop_state = NETLOOP_FAIL;
304 wget_fail("wget: store error\n", tcp_seq_num, tcp_ack_num, action);
305 net_set_state(NETLOOP_FAIL);
306 return;
307 }
308 }
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800309
310 debug_cond(DEBUG_WGET,
311 "wget: Connected Pkt %p hlen %x\n",
312 pkt, hlen);
313
314 for (i = 0; i < pkt_q_idx; i++) {
Masahisa Kojima04592ad2023-11-10 13:25:34 +0900315 int err;
316
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800317 ptr1 = map_sysmem(
318 (phys_addr_t)(pkt_q[i].pkt),
319 pkt_q[i].len);
Masahisa Kojima04592ad2023-11-10 13:25:34 +0900320 err = store_block(ptr1,
321 pkt_q[i].tcp_seq_num -
322 initial_data_seq_num,
323 pkt_q[i].len);
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800324 unmap_sysmem(ptr1);
325 debug_cond(DEBUG_WGET,
326 "wget: Connctd pkt Q %p len %x\n",
327 pkt_q[i].pkt, pkt_q[i].len);
Masahisa Kojima04592ad2023-11-10 13:25:34 +0900328 if (err) {
329 wget_loop_state = NETLOOP_FAIL;
330 wget_fail("wget: store error\n", tcp_seq_num, tcp_ack_num, action);
331 net_set_state(NETLOOP_FAIL);
332 return;
333 }
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800334 }
335 }
336 }
337 wget_send(action, tcp_seq_num, tcp_ack_num, len);
338}
339
340/**
Dmitrii Merkurev08fb8da2023-04-12 19:49:29 +0100341 * wget_handler() - TCP handler of wget
342 * @pkt: pointer to the application packet
343 * @dport: destination TCP port
344 * @sip: source IP address
345 * @sport: source TCP port
346 * @tcp_seq_num: TCP sequential number
347 * @tcp_ack_num: TCP acknowledgment number
348 * @action: TCP action (SYN, ACK, FIN, etc)
349 * @len: packet length
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800350 *
351 * In the "application push" invocation, the TCP header with all
352 * its information is pointed to by the packet pointer.
353 */
Dmitrii Merkurev08fb8da2023-04-12 19:49:29 +0100354static void wget_handler(uchar *pkt, u16 dport,
355 struct in_addr sip, u16 sport,
356 u32 tcp_seq_num, u32 tcp_ack_num,
357 u8 action, unsigned int len)
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800358{
359 enum tcp_state wget_tcp_state = tcp_get_tcp_state();
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800360
361 net_set_timeout_handler(wget_timeout, wget_timeout_handler);
362 packets++;
363
364 switch (current_wget_state) {
365 case WGET_CLOSED:
366 debug_cond(DEBUG_WGET, "wget: Handler: Error!, State wrong\n");
367 break;
368 case WGET_CONNECTING:
369 debug_cond(DEBUG_WGET,
Dmitrii Merkurev08fb8da2023-04-12 19:49:29 +0100370 "wget: Connecting In len=%x, Seq=%u, Ack=%u\n",
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800371 len, tcp_seq_num, tcp_ack_num);
372 if (!len) {
373 if (wget_tcp_state == TCP_ESTABLISHED) {
374 debug_cond(DEBUG_WGET,
375 "wget: Cting, send, len=%x\n", len);
376 wget_send(action, tcp_seq_num, tcp_ack_num,
377 len);
378 } else {
379 printf("%.*s", len, pkt);
380 wget_fail("wget: Handler Connected Fail\n",
381 tcp_seq_num, tcp_ack_num, action);
382 }
383 }
384 break;
385 case WGET_CONNECTED:
Dmitrii Merkurev08fb8da2023-04-12 19:49:29 +0100386 debug_cond(DEBUG_WGET, "wget: Connected seq=%u, len=%x\n",
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800387 tcp_seq_num, len);
388 if (!len) {
389 wget_fail("Image not found, no data returned\n",
390 tcp_seq_num, tcp_ack_num, action);
391 } else {
Dmitrii Merkurev08fb8da2023-04-12 19:49:29 +0100392 wget_connected(pkt, tcp_seq_num, action, tcp_ack_num, len);
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800393 }
394 break;
395 case WGET_TRANSFERRING:
396 debug_cond(DEBUG_WGET,
397 "wget: Transferring, seq=%x, ack=%x,len=%x\n",
398 tcp_seq_num, tcp_ack_num, len);
399
Yasuharu Shibatacab78672024-04-14 19:46:07 +0900400 if (next_data_seq_num != tcp_seq_num) {
401 debug_cond(DEBUG_WGET, "wget: seq=%x packet was lost\n", next_data_seq_num);
402 return;
403 }
404 next_data_seq_num = tcp_seq_num + len;
405
Yasuharu Shibatabeac9582024-04-16 09:26:24 +0900406 if (store_block(pkt, tcp_seq_num - initial_data_seq_num, len) != 0) {
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800407 wget_fail("wget: store error\n",
408 tcp_seq_num, tcp_ack_num, action);
Masahisa Kojima04592ad2023-11-10 13:25:34 +0900409 net_set_state(NETLOOP_FAIL);
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800410 return;
411 }
412
413 switch (wget_tcp_state) {
414 case TCP_FIN_WAIT_2:
415 wget_send(TCP_ACK, tcp_seq_num, tcp_ack_num, len);
416 fallthrough;
417 case TCP_SYN_SENT:
Dmitrii Merkurev08fb8da2023-04-12 19:49:29 +0100418 case TCP_SYN_RECEIVED:
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800419 case TCP_CLOSING:
420 case TCP_FIN_WAIT_1:
421 case TCP_CLOSED:
422 net_set_state(NETLOOP_FAIL);
423 break;
424 case TCP_ESTABLISHED:
425 wget_send(TCP_ACK, tcp_seq_num, tcp_ack_num,
426 len);
427 wget_loop_state = NETLOOP_SUCCESS;
428 break;
429 case TCP_CLOSE_WAIT: /* End of transfer */
430 current_wget_state = WGET_TRANSFERRED;
431 wget_send(action | TCP_ACK | TCP_FIN,
432 tcp_seq_num, tcp_ack_num, len);
433 break;
434 }
435 break;
436 case WGET_TRANSFERRED:
437 printf("Packets received %d, Transfer Successful\n", packets);
438 net_set_state(wget_loop_state);
439 break;
440 }
441}
442
443#define RANDOM_PORT_START 1024
444#define RANDOM_PORT_RANGE 0x4000
445
446/**
447 * random_port() - make port a little random (1024-17407)
448 *
449 * Return: random port number from 1024 to 17407
450 *
451 * This keeps the math somewhat trivial to compute, and seems to work with
452 * all supported protocols/clients/servers
453 */
454static unsigned int random_port(void)
455{
456 return RANDOM_PORT_START + (get_timer(0) % RANDOM_PORT_RANGE);
457}
458
459#define BLOCKSIZE 512
460
461void wget_start(void)
462{
463 image_url = strchr(net_boot_file_name, ':');
464 if (image_url > 0) {
465 web_server_ip = string_to_ip(net_boot_file_name);
466 ++image_url;
467 net_server_ip = web_server_ip;
468 } else {
469 web_server_ip = net_server_ip;
470 image_url = net_boot_file_name;
471 }
472
473 debug_cond(DEBUG_WGET,
474 "wget: Transfer HTTP Server %pI4; our IP %pI4\n",
475 &web_server_ip, &net_ip);
476
477 /* Check if we need to send across this subnet */
478 if (net_gateway.s_addr && net_netmask.s_addr) {
479 struct in_addr our_net;
480 struct in_addr server_net;
481
482 our_net.s_addr = net_ip.s_addr & net_netmask.s_addr;
483 server_net.s_addr = net_server_ip.s_addr & net_netmask.s_addr;
484 if (our_net.s_addr != server_net.s_addr)
485 debug_cond(DEBUG_WGET,
486 "wget: sending through gateway %pI4",
487 &net_gateway);
488 }
489 debug_cond(DEBUG_WGET, "URL '%s'\n", image_url);
490
491 if (net_boot_file_expected_size_in_blocks) {
492 debug_cond(DEBUG_WGET, "wget: Size is 0x%x Bytes = ",
493 net_boot_file_expected_size_in_blocks * BLOCKSIZE);
494 print_size(net_boot_file_expected_size_in_blocks * BLOCKSIZE,
495 "");
496 }
497 debug_cond(DEBUG_WGET,
498 "\nwget:Load address: 0x%lx\nLoading: *\b", image_load_addr);
499
Masahisa Kojima04592ad2023-11-10 13:25:34 +0900500 if (IS_ENABLED(CONFIG_LMB)) {
501 if (wget_init_load_size()) {
502 printf("\nwget error: ");
503 printf("trying to overwrite reserved memory...\n");
504 net_set_state(NETLOOP_FAIL);
505 return;
506 }
507 }
508
Ying-Chun Liu (PaulLiu)cfbae482022-11-08 14:17:29 +0800509 net_set_timeout_handler(wget_timeout, wget_timeout_handler);
510 tcp_set_tcp_handler(wget_handler);
511
512 wget_timeout_count = 0;
513 current_wget_state = WGET_CLOSED;
514
515 our_port = random_port();
516
517 /*
518 * Zero out server ether to force arp resolution in case
519 * the server ip for the previous u-boot command, for example dns
520 * is not the same as the web server ip.
521 */
522
523 memset(net_server_ethaddr, 0, 6);
524
525 wget_send(TCP_SYN, 0, 0, 0);
526}
Masahisa Kojima8cf18da2023-11-10 13:25:35 +0900527
528#if (IS_ENABLED(CONFIG_CMD_DNS))
529int wget_with_dns(ulong dst_addr, char *uri)
530{
531 int ret;
532 char *s, *host_name, *file_name, *str_copy;
533
534 /*
535 * Download file using wget.
536 *
537 * U-Boot wget takes the target uri in this format.
538 * "<http server ip>:<file path>" e.g.) 192.168.1.1:/sample/test.iso
539 * Need to resolve the http server ip address before starting wget.
540 */
541 str_copy = strdup(uri);
542 if (!str_copy)
543 return -ENOMEM;
544
545 s = str_copy + strlen("http://");
546 host_name = strsep(&s, "/");
547 if (!s) {
548 log_err("Error: invalied uri, no file path\n");
549 ret = -EINVAL;
550 goto out;
551 }
552 file_name = s;
553
554 /* TODO: If the given uri has ip address for the http server, skip dns */
555 net_dns_resolve = host_name;
556 net_dns_env_var = "httpserverip";
557 if (net_loop(DNS) < 0) {
558 log_err("Error: dns lookup of %s failed, check setup\n", net_dns_resolve);
559 ret = -EINVAL;
560 goto out;
561 }
562 s = env_get("httpserverip");
563 if (!s) {
564 ret = -EINVAL;
565 goto out;
566 }
567
568 strlcpy(net_boot_file_name, s, sizeof(net_boot_file_name));
569 strlcat(net_boot_file_name, ":/", sizeof(net_boot_file_name)); /* append '/' which is removed by strsep() */
570 strlcat(net_boot_file_name, file_name, sizeof(net_boot_file_name));
571 image_load_addr = dst_addr;
572 ret = net_loop(WGET);
573
574out:
575 free(str_copy);
576
577 return ret;
578}
579#endif
Masahisa Kojimaf01c9612023-11-10 13:25:41 +0900580
581/**
582 * wget_validate_uri() - validate the uri for wget
583 *
584 * @uri: uri string
585 *
586 * This function follows the current U-Boot wget implementation.
587 * scheme: only "http:" is supported
588 * authority:
589 * - user information: not supported
590 * - host: supported
591 * - port: not supported(always use the default port)
592 *
593 * Uri is expected to be correctly percent encoded.
594 * This is the minimum check, control codes(0x1-0x19, 0x7F, except '\0')
595 * and space character(0x20) are not allowed.
596 *
597 * TODO: stricter uri conformance check
598 *
599 * Return: true on success, false on failure
600 */
601bool wget_validate_uri(char *uri)
602{
603 char c;
604 bool ret = true;
605 char *str_copy, *s, *authority;
606
607 for (c = 0x1; c < 0x21; c++) {
608 if (strchr(uri, c)) {
609 log_err("invalid character is used\n");
610 return false;
611 }
612 }
613 if (strchr(uri, 0x7f)) {
614 log_err("invalid character is used\n");
615 return false;
616 }
617
618 if (strncmp(uri, "http://", 7)) {
619 log_err("only http:// is supported\n");
620 return false;
621 }
622 str_copy = strdup(uri);
623 if (!str_copy)
624 return false;
625
626 s = str_copy + strlen("http://");
627 authority = strsep(&s, "/");
628 if (!s) {
629 log_err("invalid uri, no file path\n");
630 ret = false;
631 goto out;
632 }
633 s = strchr(authority, '@');
634 if (s) {
635 log_err("user information is not supported\n");
636 ret = false;
637 goto out;
638 }
639 s = strchr(authority, ':');
640 if (s) {
641 log_err("user defined port is not supported\n");
642 ret = false;
643 goto out;
644 }
645
646out:
647 free(str_copy);
648
649 return ret;
650}