diff options
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | cmd/Kconfig | 13 | ||||
-rw-r--r-- | cmd/Makefile | 3 | ||||
-rw-r--r-- | cmd/lwip/Makefile | 6 | ||||
-rw-r--r-- | cmd/lwip/dhcp.c | 9 | ||||
-rw-r--r-- | cmd/lwip/dns.c (renamed from net/lwip/dns.c) | 33 | ||||
-rw-r--r-- | cmd/lwip/ping.c (renamed from net/lwip/ping.c) | 6 | ||||
-rw-r--r-- | cmd/lwip/sntp.c | 134 | ||||
-rw-r--r-- | cmd/lwip/tftp.c | 9 | ||||
-rw-r--r-- | cmd/lwip/wget.c | 222 | ||||
-rw-r--r-- | cmd/net-lwip.c | 50 | ||||
-rw-r--r-- | configs/qemu_arm64_lwip_defconfig | 1 | ||||
-rw-r--r-- | doc/README.SNTP | 17 | ||||
-rw-r--r-- | doc/usage/cmd/sntp.rst | 72 | ||||
-rw-r--r-- | doc/usage/index.rst | 1 | ||||
-rw-r--r-- | include/net-common.h | 13 | ||||
-rw-r--r-- | include/net-lwip.h | 16 | ||||
-rw-r--r-- | lib/lwip/Makefile | 1 | ||||
-rw-r--r-- | lib/lwip/u-boot/arch/cc.h | 4 | ||||
-rw-r--r-- | lib/lwip/u-boot/lwipopts.h | 8 | ||||
-rw-r--r-- | net/lwip/Makefile | 2 | ||||
-rw-r--r-- | net/lwip/dhcp.c | 1 | ||||
-rw-r--r-- | net/lwip/eth_internal.h | 35 | ||||
-rw-r--r-- | net/lwip/net-lwip.c | 81 | ||||
-rw-r--r-- | net/lwip/tftp.c | 8 | ||||
-rw-r--r-- | net/lwip/wget.c | 207 | ||||
-rw-r--r-- | net/net-common.c | 23 | ||||
-rw-r--r-- | net/sntp.c | 23 |
28 files changed, 637 insertions, 362 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index b4d5df77ff6..d5264c8f5df 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1410,6 +1410,7 @@ F: net/ NETWORK (LWIP) M: Jerome Forissier <jerome.forissier@linaro.org> S: Maintained +F: cmd/lwip/ F: cmd/net-lwip.c F: configs/qemu_arm64_lwip_defconfig F: drivers/net/sandbox-lwip.c diff --git a/cmd/Kconfig b/cmd/Kconfig index 37495c261a6..1e86773a143 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2080,12 +2080,6 @@ config CMD_CDP and to retrieve configuration data including the VLAN id using the proprietary Cisco Discovery Protocol (CDP). -config CMD_SNTP - bool "sntp" - select PROT_UDP - help - Synchronize RTC via network - config CMD_LINK_LOCAL bool "linklocal" depends on (LIB_RAND || LIB_HW_RAND) @@ -2163,6 +2157,13 @@ config CMD_PING help Send ICMP ECHO_REQUEST to network host +config CMD_SNTP + bool "sntp" + select PROT_UDP if NET + select PROT_UDP_LWIP if NET_LWIP + help + Synchronize RTC via network + config CMD_TFTPBOOT bool "tftp" select PROT_UDP_LWIP if NET_LWIP diff --git a/cmd/Makefile b/cmd/Makefile index 718eff4ed19..40f6ac4a85e 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -133,7 +133,8 @@ obj-$(CONFIG_CMD_NAND) += nand.o ifdef CONFIG_NET obj-$(CONFIG_CMD_NET) += net.o net-common.o else ifdef CONFIG_NET_LWIP -obj-$(CONFIG_CMD_NET) += net-lwip.o net-common.o +obj-$(CONFIG_CMD_NET) += net-common.o +obj-y += lwip/ endif obj-$(CONFIG_ENV_SUPPORT) += nvedit.o obj-$(CONFIG_CMD_NVEDIT_EFI) += nvedit_efi.o diff --git a/cmd/lwip/Makefile b/cmd/lwip/Makefile new file mode 100644 index 00000000000..a7f8976af3f --- /dev/null +++ b/cmd/lwip/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_CMD_DHCP) += dhcp.o +obj-$(CONFIG_CMD_DNS) += dns.o +obj-$(CONFIG_CMD_PING) += ping.o +obj-$(CONFIG_CMD_SNTP) += sntp.o +obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o +obj-$(CONFIG_CMD_WGET) += wget.o diff --git a/cmd/lwip/dhcp.c b/cmd/lwip/dhcp.c new file mode 100644 index 00000000000..3894d71f654 --- /dev/null +++ b/cmd/lwip/dhcp.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (C) 2024-2025 Linaro Ltd. */ + +#include <command.h> +#include <net.h> + +U_BOOT_CMD(dhcp, 3, 1, do_dhcp, + "boot image via network using DHCP/TFTP protocol", + "[loadAddress] [[hostIPaddr:]bootfilename]"); diff --git a/net/lwip/dns.c b/cmd/lwip/dns.c index 6862869d9e3..b5fccc7433e 100644 --- a/net/lwip/dns.c +++ b/cmd/lwip/dns.c @@ -9,6 +9,9 @@ #include <net.h> #include <time.h> +U_BOOT_CMD(dns, 3, 1, do_dns, "lookup the IP of a hostname", + "hostname [envvar]"); + #define DNS_RESEND_MS 1000 #define DNS_TIMEOUT_MS 10000 @@ -36,21 +39,18 @@ static void dns_cb(const char *name, const ip_addr_t *ipaddr, void *arg) return; } + dns_cb_arg->host_ipaddr.addr = ipaddr->addr; + if (dns_cb_arg->var) env_set(dns_cb_arg->var, ipstr); - - printf("%s\n", ipstr); } static int dns_loop(struct udevice *udev, const char *name, const char *var) { struct dns_cb_arg dns_cb_arg = { }; - bool has_server = false; struct netif *netif; ip_addr_t ipaddr; - ip_addr_t ns; ulong start; - char *nsenv; int ret; dns_cb_arg.var = var; @@ -59,22 +59,7 @@ static int dns_loop(struct udevice *udev, const char *name, const char *var) if (!netif) return CMD_RET_FAILURE; - dns_init(); - - nsenv = env_get("dnsip"); - if (nsenv && ipaddr_aton(nsenv, &ns)) { - dns_setserver(0, &ns); - has_server = true; - } - - nsenv = env_get("dnsip2"); - if (nsenv && ipaddr_aton(nsenv, &ns)) { - dns_setserver(1, &ns); - has_server = true; - } - - if (!has_server) { - log_err("No valid name server (dnsip/dnsip2)\n"); + if (net_lwip_dns_init()) { net_lwip_remove_netif(netif); return CMD_RET_FAILURE; } @@ -92,7 +77,6 @@ static int dns_loop(struct udevice *udev, const char *name, const char *var) net_lwip_rx(udev, netif); if (dns_cb_arg.done) break; - sys_check_timeouts(); if (ctrlc()) { printf("\nAbort\n"); break; @@ -103,8 +87,11 @@ static int dns_loop(struct udevice *udev, const char *name, const char *var) net_lwip_remove_netif(netif); - if (dns_cb_arg.done && dns_cb_arg.host_ipaddr.addr != 0) + if (dns_cb_arg.done && dns_cb_arg.host_ipaddr.addr != 0) { + if (!var) + printf("%s\n", ipaddr_ntoa(&ipaddr)); return CMD_RET_SUCCESS; + } return CMD_RET_FAILURE; } diff --git a/net/lwip/ping.c b/cmd/lwip/ping.c index d8042ceecf9..87f8e958e48 100644 --- a/net/lwip/ping.c +++ b/cmd/lwip/ping.c @@ -13,6 +13,9 @@ #include <net.h> #include <time.h> +U_BOOT_CMD(ping, 2, 1, do_ping, "send ICMP ECHO_REQUEST to network host", + "pingAddressOrHostName"); + #define PING_DELAY_MS 1000 #define PING_COUNT 5 /* Ping identifier - must fit on a u16_t */ @@ -136,7 +139,6 @@ static int ping_loop(struct udevice *udev, const ip_addr_t *addr) ping_send(&ctx); do { - sys_check_timeouts(); net_lwip_rx(udev, netif); if (ctx.alive) break; @@ -165,7 +167,7 @@ int do_ping(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) if (argc < 2) return CMD_RET_USAGE; - if (!ipaddr_aton(argv[1], &addr)) + if (net_lwip_dns_resolve(argv[1], &addr)) return CMD_RET_USAGE; restart: diff --git a/cmd/lwip/sntp.c b/cmd/lwip/sntp.c new file mode 100644 index 00000000000..ae02bb11040 --- /dev/null +++ b/cmd/lwip/sntp.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (C) 2025 Linaro Ltd. */ + +#include <command.h> +#include <console.h> +#include <dm/device.h> +#include <env.h> +#include <lwip/apps/sntp.h> +#include <lwip/timeouts.h> +#include <net.h> + +U_BOOT_CMD(sntp, 2, 1, do_sntp, "synchronize RTC via network", + "[NTPServerNameOrIp]"); + +#define SNTP_TIMEOUT 10000 + +static enum done_state { + NOT_DONE = 0, + SUCCESS, + ABORTED, + TIMED_OUT +} sntp_state; + +static void no_response(void *arg) +{ + sntp_state = TIMED_OUT; +} + +/* Called by lwIP via the SNTP_SET_SYSTEM_TIME() macro */ +void sntp_set_system_time(uint32_t seconds) +{ + char *toff; + int net_ntp_time_offset = 0; + + toff = env_get("timeoffset"); + if (toff) + net_ntp_time_offset = simple_strtol(toff, NULL, 10); + + net_sntp_set_rtc(seconds + net_ntp_time_offset); + sntp_state = SUCCESS; +} + +static bool ntp_server_known(void) +{ + int i; + + for (i = 0; i < SNTP_MAX_SERVERS; i++) { + const ip_addr_t *ip = sntp_getserver(i); + + if (ip && ip->addr) + return true; + } + + return false; +} + +static int sntp_loop(struct udevice *udev, ip_addr_t *srvip) +{ + struct netif *netif; + + netif = net_lwip_new_netif(udev); + if (!netif) + return -1; + + sntp_state = NOT_DONE; + + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_servermode_dhcp(CONFIG_IS_ENABLED(CMD_DHCP)); + if (srvip) { + sntp_setserver(0, srvip); + } else { + if (!ntp_server_known()) { + log_err("error: ntpserverip not set\n"); + return -1; + } + } + sntp_init(); + + sys_timeout(SNTP_TIMEOUT, no_response, NULL); + while (sntp_state == NOT_DONE) { + net_lwip_rx(udev, netif); + sys_check_timeouts(); + if (ctrlc()) { + printf("\nAbort\n"); + sntp_state = ABORTED; + break; + } + } + sys_untimeout(no_response, NULL); + + sntp_stop(); + net_lwip_remove_netif(netif); + + if (sntp_state == SUCCESS) + return 0; + + return -1; +} + +int do_sntp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + ip_addr_t *srvip; + char *server; + ip_addr_t ipaddr; + + switch (argc) { + case 1: + srvip = NULL; + server = env_get("ntpserverip"); + if (server) { + if (!ipaddr_aton(server, &ipaddr)) { + printf("ntpserverip is invalid\n"); + return CMD_RET_FAILURE; + } + srvip = &ipaddr; + } + break; + case 2: + if (net_lwip_dns_resolve(argv[1], &ipaddr)) + return CMD_RET_FAILURE; + srvip = &ipaddr; + break; + default: + return CMD_RET_USAGE; + } + + if (net_lwip_eth_start() < 0) + return CMD_RET_FAILURE; + + if (sntp_loop(eth_get_dev(), srvip) < 0) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} diff --git a/cmd/lwip/tftp.c b/cmd/lwip/tftp.c new file mode 100644 index 00000000000..6bb7a3733a2 --- /dev/null +++ b/cmd/lwip/tftp.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (C) 2024-2025 Linaro Ltd. */ + +#include <command.h> +#include <net.h> + +U_BOOT_CMD(tftpboot, 3, 0, do_tftpb, + "boot image via network using TFTP protocol", + "[loadAddress] [[hostIPaddr:]bootfilename]"); diff --git a/cmd/lwip/wget.c b/cmd/lwip/wget.c new file mode 100644 index 00000000000..fc9bc11cd83 --- /dev/null +++ b/cmd/lwip/wget.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (C) 2024-2025 Linaro Ltd. */ + +#include <command.h> +#include <env.h> +#include <image.h> +#include <net.h> +#include <lwip/altcp_tls.h> + +U_BOOT_CMD(wget, 4, 1, do_wget, + "boot image via network using HTTP/HTTPS protocol" +#if defined(CONFIG_WGET_CACERT) + "\nwget cacert - configure wget root certificates" +#endif + , + "[loadAddress] url\n" + "wget [loadAddress] [host:]path\n" + " - load file" +#if defined(CONFIG_WGET_CACERT) + "\nwget cacert <address> <length>\n" + " - provide CA certificates (0 0 to remove current)" + "\nwget cacert none|optional|required\n" + " - set server certificate verification mode (default: optional)" +#if defined(CONFIG_WGET_BUILTIN_CACERT) + "\nwget cacert builtin\n" + " - use the builtin CA certificates" +#endif +#endif +); + +#if CONFIG_IS_ENABLED(WGET_CACERT) || CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) +char *cacert; +size_t cacert_size; +enum auth_mode cacert_auth_mode = AUTH_OPTIONAL; + +#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) +extern const char builtin_cacert[]; +extern const size_t builtin_cacert_size; +bool cacert_initialized; +#endif + +static int _set_cacert(const void *addr, size_t sz) +{ + mbedtls_x509_crt crt; + void *p; + int ret; + + if (cacert) + free(cacert); + + if (!addr) { + cacert = NULL; + cacert_size = 0; + return CMD_RET_SUCCESS; + } + + p = malloc(sz); + if (!p) + return CMD_RET_FAILURE; + cacert = p; + cacert_size = sz; + + memcpy(cacert, (void *)addr, sz); + + mbedtls_x509_crt_init(&crt); + ret = mbedtls_x509_crt_parse(&crt, cacert, cacert_size); + if (ret) { + if (!wget_info->silent) + printf("Could not parse certificates (%d)\n", ret); + free(cacert); + cacert = NULL; + cacert_size = 0; + return CMD_RET_FAILURE; + } + +#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) + cacert_initialized = true; +#endif + return CMD_RET_SUCCESS; +} + +#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) +int set_cacert_builtin(void) +{ + cacert_auth_mode = AUTH_REQUIRED; + return _set_cacert(builtin_cacert, builtin_cacert_size); +} +#endif +#endif /* CONFIG_WGET_CACERT || CONFIG_WGET_BUILTIN_CACERT */ + +#if CONFIG_IS_ENABLED(WGET_CACERT) +static int set_auth(enum auth_mode auth) +{ + cacert_auth_mode = auth; + + return CMD_RET_SUCCESS; +} + +static int set_cacert(char * const saddr, char * const ssz) +{ + ulong addr, sz; + + addr = hextoul(saddr, NULL); + sz = hextoul(ssz, NULL); + + return _set_cacert((void *)addr, sz); +} +#endif + +/* + * Legacy syntax support + * Convert [<server_name_or_ip>:]filename into a URL if needed + */ +static int parse_legacy_arg(char *arg, char *nurl, size_t rem) +{ + char *p = nurl; + size_t n; + char *col = strchr(arg, ':'); + char *env; + char *server; + char *path; + + if (strstr(arg, "http") == arg) { + n = snprintf(nurl, rem, "%s", arg); + if (n < 0 || n > rem) + return -1; + return 0; + } + + n = snprintf(p, rem, "%s", "http://"); + if (n < 0 || n > rem) + return -1; + p += n; + rem -= n; + + if (col) { + n = col - arg; + server = arg; + path = col + 1; + } else { + env = env_get("httpserverip"); + if (!env) + env = env_get("serverip"); + if (!env) { + log_err("error: httpserver/serverip has to be set\n"); + return -1; + } + n = strlen(env); + server = env; + path = arg; + } + + if (rem < n) + return -1; + strncpy(p, server, n); + p += n; + rem -= n; + if (rem < 1) + return -1; + *p = '/'; + p++; + rem--; + n = strlen(path); + if (rem < n) + return -1; + strncpy(p, path, n); + p += n; + rem -= n; + if (rem < 1) + return -1; + *p = '\0'; + + return 0; +} + +int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + char *end; + char *url; + ulong dst_addr; + char nurl[1024]; + +#if CONFIG_IS_ENABLED(WGET_CACERT) + if (argc == 4 && !strncmp(argv[1], "cacert", strlen("cacert"))) + return set_cacert(argv[2], argv[3]); + if (argc == 3 && !strncmp(argv[1], "cacert", strlen("cacert"))) { +#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) + if (!strncmp(argv[2], "builtin", strlen("builtin"))) + return set_cacert_builtin(); +#endif + if (!strncmp(argv[2], "none", strlen("none"))) + return set_auth(AUTH_NONE); + if (!strncmp(argv[2], "optional", strlen("optional"))) + return set_auth(AUTH_OPTIONAL); + if (!strncmp(argv[2], "required", strlen("required"))) + return set_auth(AUTH_REQUIRED); + return CMD_RET_USAGE; + } +#endif + + if (argc < 2 || argc > 3) + return CMD_RET_USAGE; + + dst_addr = hextoul(argv[1], &end); + if (end == (argv[1] + strlen(argv[1]))) { + if (argc < 3) + return CMD_RET_USAGE; + url = argv[2]; + } else { + dst_addr = image_load_addr; + url = argv[1]; + } + + if (parse_legacy_arg(url, nurl, sizeof(nurl))) + return CMD_RET_FAILURE; + + wget_info = &default_wget_info; + if (wget_do_request(dst_addr, nurl)) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} diff --git a/cmd/net-lwip.c b/cmd/net-lwip.c deleted file mode 100644 index cecf8d02555..00000000000 --- a/cmd/net-lwip.c +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* Copyright (C) 2024 Linaro Ltd. */ - -#include <command.h> -#include <net.h> - -#if defined(CONFIG_CMD_DHCP) -U_BOOT_CMD(dhcp, 3, 1, do_dhcp, - "boot image via network using DHCP/TFTP protocol", - "[loadAddress] [[hostIPaddr:]bootfilename]"); -#endif - -#if defined(CONFIG_CMD_PING) -U_BOOT_CMD(ping, 2, 1, do_ping, "send ICMP ECHO_REQUEST to network host", - "pingAddress"); -#endif - -#if defined(CONFIG_CMD_TFTPBOOT) -U_BOOT_CMD(tftpboot, 3, 0, do_tftpb, - "boot image via network using TFTP protocol", - "[loadAddress] [[hostIPaddr:]bootfilename]"); -#endif - -#if defined(CONFIG_CMD_DNS) -U_BOOT_CMD(dns, 3, 1, do_dns, "lookup the IP of a hostname", - "hostname [envvar]"); -#endif - -#if defined(CONFIG_CMD_WGET) -U_BOOT_CMD(wget, 4, 1, do_wget, - "boot image via network using HTTP/HTTPS protocol" -#if defined(CONFIG_WGET_CACERT) - "\nwget cacert - configure wget root certificates" -#endif - , - "[loadAddress] url\n" - "wget [loadAddress] [host:]path\n" - " - load file" -#if defined(CONFIG_WGET_CACERT) - "\nwget cacert <address> <length>\n" - " - provide CA certificates (0 0 to remove current)" - "\nwget cacert none|optional|required\n" - " - set server certificate verification mode (default: optional)" -#if defined(CONFIG_WGET_BUILTIN_CACERT) - "\nwget cacert builtin\n" - " - use the builtin CA certificates" -#endif -#endif -); -#endif diff --git a/configs/qemu_arm64_lwip_defconfig b/configs/qemu_arm64_lwip_defconfig index 814e98729a3..e8f976efaf7 100644 --- a/configs/qemu_arm64_lwip_defconfig +++ b/configs/qemu_arm64_lwip_defconfig @@ -5,6 +5,7 @@ CONFIG_ARCH_QEMU=y CONFIG_NET_LWIP=y CONFIG_CMD_DNS=y +CONFIG_CMD_SNTP=y CONFIG_CMD_WGET=y CONFIG_EFI_HTTP_BOOT=y CONFIG_WGET_HTTPS=y diff --git a/doc/README.SNTP b/doc/README.SNTP deleted file mode 100644 index da9ec459ad4..00000000000 --- a/doc/README.SNTP +++ /dev/null @@ -1,17 +0,0 @@ -To use SNTP support, add define CONFIG_CMD_SNTP to the -configuration file of the board. - -The "sntp" command gets network time from NTP time server and -syncronize RTC of the board. This command needs the command line -parameter of server's IP address or environment variable -"ntpserverip". The network time is sent as UTC. So if you want to -set local time to RTC, set the offset in second from UTC to the -environment variable "time offset". - -If the DHCP server provides time server's IP or time offset, you -don't need to set the above environment variables yourself. - -Current limitations of SNTP support: -1. The roundtrip time is ignored. -2. Only the 1st NTP server IP, in the option ntp-servers of DHCP, will - be used. diff --git a/doc/usage/cmd/sntp.rst b/doc/usage/cmd/sntp.rst new file mode 100644 index 00000000000..d97f83053f7 --- /dev/null +++ b/doc/usage/cmd/sntp.rst @@ -0,0 +1,72 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +.. index:: + single: sntp (command) + +sntp command +============ + +Synopsis +-------- + +:: + + sntp [serverip] + sntp [servername] # NET_LWIP=y && CMD_DNS=y only + + +Description +----------- + +The sntp command gets the current time from an NTP time server and +syncronizes the Real Time Clock (RTC) of the board. This command needs +the server's IP address to be given on the command line or via the +`ntpserverip` environment variable. + +The address of the NTP server does not need to be given if the DHCP server +provides one. The legacy network stack (`CONFIG_NET=y`) can only use the +first NTP server provided in the `ntp-servers` DHCP option. + +When the network stack is lwIP (`CONFIG_NET_LWIP=y`) and the dns command +is enabled (`CONFIG_CMD_DNS=y`), then the sntp command accepts a server +name as an argument. + +The network time is sent as UTC. So, if you want to set the RTC to any local +time different from UTC, you need to set the `timeoffset` environment variable. + +Round-trip delay compensation is not implemented/not enabled. In practice +this should not matter much given that the RTC API does not have sub-second +resolution, and round-trip times are typically 10 to 100 ms at most. + +Examples +-------- + +:: + + => setenv ntpserverip 109.190.177.205 + => date + Date: 2025-06-16 (Monday) Time: 15:19:35 + => date reset + Reset RTC... + Date: 2000-01-01 (Saturday) Time: 0:00:00 + => date + Date: 2000-01-01 (Saturday) Time: 0:00:03 + => sntp + Date: 2025-06-16 Time: 15:19:43 + => date + Date: 2025-06-16 (Monday) Time: 15:19:47 + => setenv timeoffset 7200 + => sntp + Date: 2025-06-16 Time: 17:19:55 + => date + Date: 2025-06-16 (Monday) Time: 17:19:57 + +With `CONFIG_NET_LWIP=y` and `CONFIG_CMD_DNS=y`: + +:: + + => date reset + Reset RTC... + Date: 2000-01-01 (Saturday) Time: 0:00:00 + => sntp 0.us.pool.ntp.org + Date: 2025-06-16 Time: 15:10:59 diff --git a/doc/usage/index.rst b/doc/usage/index.rst index c5b45fd9290..e9e0bd04e05 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -119,6 +119,7 @@ Shell commands cmd/sleep cmd/sm cmd/smbios + cmd/sntp cmd/sound cmd/source cmd/tcpm diff --git a/include/net-common.h b/include/net-common.h index c04f86bdfcc..1112af381a9 100644 --- a/include/net-common.h +++ b/include/net-common.h @@ -492,6 +492,17 @@ int dhcp_run(ulong addr, const char *fname, bool autoload); int do_ping(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); /** + * do_sntp - Run the sntp command + * + * @cmdtp: Unused + * @flag: Command flags (CMD_FLAG_...) + * @argc: Number of arguments + * @argv: List of arguments + * Return: result (see enum command_ret_t) + */ +int do_sntp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); + +/** * do_tftpb - Run the tftpboot command * * @cmdtp: Command information for tftpboot @@ -574,4 +585,6 @@ extern struct wget_http_info default_wget_info; extern struct wget_http_info *wget_info; int wget_request(ulong dst_addr, char *uri, struct wget_http_info *info); +void net_sntp_set_rtc(u32 seconds); + #endif /* __NET_COMMON_H__ */ diff --git a/include/net-lwip.h b/include/net-lwip.h index b762956e8fd..f54f23471f1 100644 --- a/include/net-lwip.h +++ b/include/net-lwip.h @@ -6,6 +6,20 @@ #include <lwip/ip4.h> #include <lwip/netif.h> +/* HTTPS authentication mode */ +enum auth_mode { + AUTH_NONE, + AUTH_OPTIONAL, + AUTH_REQUIRED, +}; + +extern char *cacert; +extern size_t cacert_size; +extern enum auth_mode cacert_auth_mode; +extern bool cacert_initialized; + +int set_cacert_builtin(void); + enum proto_t { TFTPGET }; @@ -17,12 +31,14 @@ static inline int eth_is_on_demand_init(void) int eth_init_state_only(void); /* Set active state */ +int net_lwip_dns_init(void); int net_lwip_eth_start(void); struct netif *net_lwip_new_netif(struct udevice *udev); struct netif *net_lwip_new_netif_noip(struct udevice *udev); void net_lwip_remove_netif(struct netif *netif); struct netif *net_lwip_get_netif(void); int net_lwip_rx(struct udevice *udev, struct netif *netif); +int net_lwip_dns_resolve(char *name_or_ip, ip_addr_t *ip); /** * wget_validate_uri() - varidate the uri diff --git a/lib/lwip/Makefile b/lib/lwip/Makefile index e9e8caee93a..c3f0e916f66 100644 --- a/lib/lwip/Makefile +++ b/lib/lwip/Makefile @@ -13,6 +13,7 @@ obj-y += \ lwip/src/api/sockets.o \ lwip/src/api/tcpip.o \ lwip/src/apps/http/http_client.o \ + lwip/src/apps/sntp/sntp.o \ lwip/src/apps/tftp/tftp.o \ lwip/src/core/altcp_alloc.o \ lwip/src/core/altcp.o \ diff --git a/lib/lwip/u-boot/arch/cc.h b/lib/lwip/u-boot/arch/cc.h index 6104c296f6f..f91127ac565 100644 --- a/lib/lwip/u-boot/arch/cc.h +++ b/lib/lwip/u-boot/arch/cc.h @@ -43,4 +43,8 @@ #define BYTE_ORDER BIG_ENDIAN #endif +#define SNTP_STARTUP_DELAY 0 +void sntp_set_system_time(uint32_t sec); +#define SNTP_SET_SYSTEM_TIME(sec) sntp_set_system_time(sec) + #endif /* LWIP_ARCH_CC_H */ diff --git a/lib/lwip/u-boot/lwipopts.h b/lib/lwip/u-boot/lwipopts.h index edac74ff7a2..46af91f9410 100644 --- a/lib/lwip/u-boot/lwipopts.h +++ b/lib/lwip/u-boot/lwipopts.h @@ -72,8 +72,8 @@ #define IP_FORWARD 0 #define IP_OPTIONS_ALLOWED 1 -#define IP_REASSEMBLY 0 -#define IP_FRAG 0 +#define IP_REASSEMBLY 1 +#define IP_FRAG 1 #define IP_REASS_MAXAGE 3 #define IP_REASS_MAX_PBUFS 4 #define IP_FRAG_USES_STATIC_BUF 0 @@ -162,4 +162,8 @@ #define LWIP_ALTCP_TLS_MBEDTLS 1 #endif +#if defined(CONFIG_CMD_SNTP) +#define LWIP_DHCP_GET_NTP_SRV 1 +#endif + #endif /* LWIP_UBOOT_LWIPOPTS_H */ diff --git a/net/lwip/Makefile b/net/lwip/Makefile index 5df222589b8..97299d9b542 100644 --- a/net/lwip/Makefile +++ b/net/lwip/Makefile @@ -2,8 +2,6 @@ ccflags-y += -I$(srctree)/lib/lwip/lwip/src/include -I$(srctree)/lib/lwip/u-boot 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 obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o obj-$(CONFIG_WGET) += wget.o diff --git a/net/lwip/dhcp.c b/net/lwip/dhcp.c index 043d2ab6e94..4c9cb0ecaa0 100644 --- a/net/lwip/dhcp.c +++ b/net/lwip/dhcp.c @@ -58,7 +58,6 @@ static int dhcp_loop(struct udevice *udev) /* Wait for DHCP to complete */ do { net_lwip_rx(udev, netif); - sys_check_timeouts(); bound = dhcp_supplied_address(netif); if (bound) break; diff --git a/net/lwip/eth_internal.h b/net/lwip/eth_internal.h deleted file mode 100644 index 87561d5b214..00000000000 --- a/net/lwip/eth_internal.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * (C) Copyright 2001-2015 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * Joe Hershberger, National Instruments - */ - -#ifndef __ETH_INTERNAL_H -#define __ETH_INTERNAL_H - -/* Do init that is common to driver model and legacy networking */ -void eth_common_init(void); - -/** - * eth_env_set_enetaddr_by_index() - set the MAC address environment variable - * - * This sets up an environment variable with the given MAC address (@enetaddr). - * The environment variable to be set is defined by <@base_name><@index>addr. - * If @index is 0 it is omitted. For common Ethernet this means ethaddr, - * eth1addr, etc. - * - * @base_name: Base name for variable, typically "eth" - * @index: Index of interface being updated (>=0) - * @enetaddr: Pointer to MAC address to put into the variable - * Return: 0 if OK, other value on error - */ -int eth_env_set_enetaddr_by_index(const char *base_name, int index, - uchar *enetaddr); - -int eth_mac_skip(int index); -void eth_current_changed(void); -void eth_set_dev(struct udevice *dev); -void eth_set_current_to_next(void); - -#endif diff --git a/net/lwip/net-lwip.c b/net/lwip/net-lwip.c index abc52b32049..3918d57d7e5 100644 --- a/net/lwip/net-lwip.c +++ b/net/lwip/net-lwip.c @@ -7,15 +7,19 @@ #include <dm/device.h> #include <dm/uclass.h> #include <hexdump.h> +#include <linux/kernel.h> #include <lwip/ip4_addr.h> +#include <lwip/dns.h> #include <lwip/err.h> #include <lwip/netif.h> #include <lwip/pbuf.h> #include <lwip/etharp.h> #include <lwip/init.h> #include <lwip/prot/etharp.h> +#include <lwip/timeouts.h> #include <net.h> #include <timer.h> +#include <u-boot/schedule.h> /* xx:xx:xx:xx:xx:xx\0 */ #define MAC_ADDR_STRLEN 18 @@ -139,6 +143,40 @@ static int get_udev_ipv4_info(struct udevice *dev, ip4_addr_t *ip, } /* + * Initialize DNS via env + */ +int net_lwip_dns_init(void) +{ +#if CONFIG_IS_ENABLED(CMD_DNS) + bool has_server = false; + ip_addr_t ns; + char *nsenv; + + nsenv = env_get("dnsip"); + if (nsenv && ipaddr_aton(nsenv, &ns)) { + dns_setserver(0, &ns); + has_server = true; + } + + nsenv = env_get("dnsip2"); + if (nsenv && ipaddr_aton(nsenv, &ns)) { + dns_setserver(1, &ns); + has_server = true; + } + + if (!has_server) { + log_err("No valid name server (dnsip/dnsip2)\n"); + return -EINVAL; + } + + return 0; +#else + log_err("DNS disabled\n"); + return -EINVAL; +#endif +} + +/* * Initialize the network stack if needed and start the current device if valid */ int net_lwip_eth_start(void) @@ -285,6 +323,11 @@ int net_lwip_rx(struct udevice *udev, struct netif *netif) int len; int i; + /* lwIP timers */ + sys_check_timeouts(); + /* Other tasks and actions */ + schedule(); + if (!eth_is_active(udev)) return -EINVAL; @@ -316,6 +359,44 @@ int net_lwip_rx(struct udevice *udev, struct netif *netif) return len; } +/** + * net_lwip_dns_resolve() - find IP address from name or IP + * + * @name_or_ip: host name or IP address + * @ip: output IP address + * + * Return value: 0 on success, -1 on failure. + */ +int net_lwip_dns_resolve(char *name_or_ip, ip_addr_t *ip) +{ +#if defined(CONFIG_CMD_DNS) + char *var = "_dnsres"; + char *argv[] = { "dns", name_or_ip, var, NULL }; + int argc = ARRAY_SIZE(argv) - 1; +#endif + + if (ipaddr_aton(name_or_ip, ip)) + return 0; + +#if defined(CONFIG_CMD_DNS) + if (do_dns(NULL, 0, argc, argv) != CMD_RET_SUCCESS) + return -1; + + name_or_ip = env_get(var); + if (!name_or_ip) + return -1; + + if (!ipaddr_aton(name_or_ip, ip)) + return -1; + + env_set(var, NULL); + + return 0; +#else + return -1; +#endif +} + void net_process_received_packet(uchar *in_packet, int len) { #if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER) diff --git a/net/lwip/tftp.c b/net/lwip/tftp.c index b7eb486ef77..94bacf63075 100644 --- a/net/lwip/tftp.c +++ b/net/lwip/tftp.c @@ -157,8 +157,10 @@ static void no_response(void *arg) static int tftp_loop(struct udevice *udev, ulong addr, char *fname, ip_addr_t srvip, uint16_t srvport) { + int blksize = CONFIG_TFTP_BLOCKSIZE; struct netif *netif; struct tftp_ctx ctx; + const char *ep; err_t err; if (!fname || addr == 0) @@ -187,7 +189,10 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname, if (!(err == ERR_OK || err == ERR_USE)) log_err("tftp_init_client err: %d\n", err); - tftp_client_set_blksize(CONFIG_TFTP_BLOCKSIZE); + ep = env_get("tftpblocksize"); + if (ep) + blksize = simple_strtol(ep, NULL, 10); + tftp_client_set_blksize(blksize); ctx.start_time = get_timer(0); err = tftp_get(&ctx, &srvip, srvport, fname, TFTP_MODE_OCTET); @@ -201,7 +206,6 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname, sys_timeout(NO_RSP_TIMEOUT_MS, no_response, &ctx); while (!ctx.done) { net_lwip_rx(udev, netif); - sys_check_timeouts(); if (ctrlc()) { printf("\nAbort\n"); ctx.done = ABORTED; diff --git a/net/lwip/wget.c b/net/lwip/wget.c index f4fd9718285..55bd2b72e26 100644 --- a/net/lwip/wget.c +++ b/net/lwip/wget.c @@ -6,7 +6,6 @@ #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" @@ -138,72 +137,6 @@ static int parse_url(char *url, char *host, u16 *port, char **path, return 0; } -/* - * Legacy syntax support - * Convert [<server_name_or_ip>:]filename into a URL if needed - */ -static int parse_legacy_arg(char *arg, char *nurl, size_t rem) -{ - char *p = nurl; - size_t n; - char *col = strchr(arg, ':'); - char *env; - char *server; - char *path; - - if (strstr(arg, "http") == arg) { - n = snprintf(nurl, rem, "%s", arg); - if (n < 0 || n > rem) - return -1; - return 0; - } - - n = snprintf(p, rem, "%s", "http://"); - if (n < 0 || n > rem) - return -1; - p += n; - rem -= n; - - if (col) { - n = col - arg; - server = arg; - path = col + 1; - } else { - env = env_get("httpserverip"); - if (!env) - env = env_get("serverip"); - if (!env) { - log_err("error: httpserver/serverip has to be set\n"); - return -1; - } - n = strlen(env); - server = env; - path = arg; - } - - if (rem < n) - return -1; - strncpy(p, server, n); - p += n; - rem -= n; - if (rem < 1) - return -1; - *p = '/'; - p++; - rem--; - n = strlen(path); - if (rem < n) - return -1; - strncpy(p, path, n); - p += n; - rem -= n; - if (rem < 1) - return -1; - *p = '\0'; - - return 0; -} - /** * store_block() - copy received data * @@ -338,94 +271,10 @@ static err_t httpc_headers_done_cb(httpc_state_t *connection, void *arg, struct return ERR_OK; } -#if CONFIG_IS_ENABLED(WGET_HTTPS) -enum auth_mode { - AUTH_NONE, - AUTH_OPTIONAL, - AUTH_REQUIRED, -}; - -static char *cacert; -static size_t cacert_size; -static enum auth_mode cacert_auth_mode = AUTH_OPTIONAL; -#endif #if CONFIG_IS_ENABLED(WGET_CACERT) -static int set_auth(enum auth_mode auth) -{ - cacert_auth_mode = auth; - - return CMD_RET_SUCCESS; -} #endif -#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) -extern const char builtin_cacert[]; -extern const size_t builtin_cacert_size; -static bool cacert_initialized; -#endif - -#if CONFIG_IS_ENABLED(WGET_CACERT) || CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) -static int _set_cacert(const void *addr, size_t sz) -{ - mbedtls_x509_crt crt; - void *p; - int ret; - - if (cacert) - free(cacert); - - if (!addr) { - cacert = NULL; - cacert_size = 0; - return CMD_RET_SUCCESS; - } - - p = malloc(sz); - if (!p) - return CMD_RET_FAILURE; - cacert = p; - cacert_size = sz; - - memcpy(cacert, (void *)addr, sz); - - mbedtls_x509_crt_init(&crt); - ret = mbedtls_x509_crt_parse(&crt, cacert, cacert_size); - if (ret) { - if (!wget_info->silent) - printf("Could not parse certificates (%d)\n", ret); - free(cacert); - cacert = NULL; - cacert_size = 0; - return CMD_RET_FAILURE; - } - -#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) - cacert_initialized = true; -#endif - return CMD_RET_SUCCESS; -} - -#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) -static int set_cacert_builtin(void) -{ - return _set_cacert(builtin_cacert, builtin_cacert_size); -} -#endif - -#if CONFIG_IS_ENABLED(WGET_CACERT) -static int set_cacert(char * const saddr, char * const ssz) -{ - ulong addr, sz; - - addr = hextoul(saddr, NULL); - sz = hextoul(ssz, NULL); - - return _set_cacert((void *)addr, sz); -} -#endif -#endif /* CONFIG_WGET_CACERT || CONFIG_WGET_BUILTIN_CACERT */ - int wget_do_request(ulong dst_addr, char *uri) { #if CONFIG_IS_ENABLED(WGET_HTTPS) @@ -461,12 +310,17 @@ int wget_do_request(ulong dst_addr, char *uri) if (!netif) return -1; + /* if URL with hostname init dns */ + if (!ipaddr_aton(ctx.server_name, NULL) && net_lwip_dns_init()) + return CMD_RET_FAILURE; + memset(&conn, 0, sizeof(conn)); #if CONFIG_IS_ENABLED(WGET_HTTPS) if (is_https) { char *ca; size_t ca_sz; +#if CONFIG_IS_ENABLED(WGET_CACERT) || CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) #if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) if (!cacert_initialized) set_cacert_builtin(); @@ -493,7 +347,7 @@ int wget_do_request(ulong dst_addr, char *uri) * with no verification if not. */ } - +#endif if (!ca && !wget_info->silent) { printf("WARNING: no CA certificates, "); printf("HTTPS connections not authenticated\n"); @@ -526,7 +380,6 @@ int wget_do_request(ulong dst_addr, char *uri) while (!ctx.done) { net_lwip_rx(udev, netif); - sys_check_timeouts(); if (ctrlc()) break; } @@ -542,54 +395,6 @@ int wget_do_request(ulong dst_addr, char *uri) return -1; } -int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) -{ - char *end; - char *url; - ulong dst_addr; - char nurl[1024]; - -#if CONFIG_IS_ENABLED(WGET_CACERT) - if (argc == 4 && !strncmp(argv[1], "cacert", strlen("cacert"))) - return set_cacert(argv[2], argv[3]); - if (argc == 3 && !strncmp(argv[1], "cacert", strlen("cacert"))) { -#if CONFIG_IS_ENABLED(WGET_BUILTIN_CACERT) - if (!strncmp(argv[2], "builtin", strlen("builtin"))) - return set_cacert_builtin(); -#endif - if (!strncmp(argv[2], "none", strlen("none"))) - return set_auth(AUTH_NONE); - if (!strncmp(argv[2], "optional", strlen("optional"))) - return set_auth(AUTH_OPTIONAL); - if (!strncmp(argv[2], "required", strlen("required"))) - return set_auth(AUTH_REQUIRED); - return CMD_RET_USAGE; - } -#endif - - if (argc < 2 || argc > 3) - return CMD_RET_USAGE; - - dst_addr = hextoul(argv[1], &end); - if (end == (argv[1] + strlen(argv[1]))) { - if (argc < 3) - return CMD_RET_USAGE; - url = argv[2]; - } else { - dst_addr = image_load_addr; - url = argv[1]; - } - - if (parse_legacy_arg(url, nurl, sizeof(nurl))) - return CMD_RET_FAILURE; - - wget_info = &default_wget_info; - if (wget_do_request(dst_addr, nurl)) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; -} - /** * wget_validate_uri() - validate the uri for wget * diff --git a/net/net-common.c b/net/net-common.c index e01b0da7d7b..b064557d524 100644 --- a/net/net-common.c +++ b/net/net-common.c @@ -1,5 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 + +#include <dm/uclass.h> #include <net-common.h> +#include <linux/time.h> +#include <rtc.h> void copy_filename(char *dst, const char *src, int size) { @@ -25,3 +29,22 @@ 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); } + +void net_sntp_set_rtc(u32 seconds) +{ + struct rtc_time tm; + struct udevice *dev; + int ret; + + rtc_to_tm(seconds, &tm); + + ret = uclass_get_device(UCLASS_RTC, 0, &dev); + if (ret) + printf("SNTP: cannot find RTC: err=%d\n", ret); + else + dm_rtc_set(dev, &tm); + + printf("Date: %4d-%02d-%02d Time: %2d:%02d:%02d\n", + tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +} diff --git a/net/sntp.c b/net/sntp.c index 73d1d87d38b..77cee0046bd 100644 --- a/net/sntp.c +++ b/net/sntp.c @@ -57,8 +57,7 @@ static void sntp_handler(uchar *pkt, unsigned dest, struct in_addr sip, unsigned src, unsigned len) { struct sntp_pkt_t *rpktp = (struct sntp_pkt_t *)pkt; - struct rtc_time tm; - ulong seconds; + u32 seconds; debug("%s\n", __func__); @@ -69,24 +68,8 @@ static void sntp_handler(uchar *pkt, unsigned dest, struct in_addr sip, * As the RTC's used in U-Boot support second resolution only * we simply ignore the sub-second field. */ - memcpy(&seconds, &rpktp->transmit_timestamp, sizeof(ulong)); - - rtc_to_tm(ntohl(seconds) - 2208988800UL + net_ntp_time_offset, &tm); -#ifdef CONFIG_DM_RTC - struct udevice *dev; - int ret; - - ret = uclass_get_device(UCLASS_RTC, 0, &dev); - if (ret) - printf("SNTP: cannot find RTC: err=%d\n", ret); - else - dm_rtc_set(dev, &tm); -#elif defined(CONFIG_CMD_DATE) - rtc_set(&tm); -#endif - printf("Date: %4d-%02d-%02d Time: %2d:%02d:%02d\n", - tm.tm_year, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); + memcpy(&seconds, &rpktp->transmit_timestamp, sizeof(seconds)); + net_sntp_set_rtc(ntohl(seconds) - 2208988800UL + net_ntp_time_offset); net_set_state(NETLOOP_SUCCESS); } |