[PATCH 10/17] net: tftp: Add IPv6 support for tftpboot
Ramon Fried
rfried.dev at gmail.com
Mon Sep 12 09:20:54 CEST 2022
On Tue, Sep 6, 2022 at 6:10 PM Viacheslav Mitrofanov
<v.v.mitrofanov at yadro.com> wrote:
>
> The command tftpboot uses IPv4 by default. Add the possibility to use IPv6
> instead. If an address in the command is an IPv6 address it will use IPv6
> to boot or if there is a suffix -ipv6 in the end of the command it also
> force using IPv6. All other tftpboot features and parameters are left
> the same.
>
> Signed-off-by: Viacheslav Mitrofanov <v.v.mitrofanov at yadro.com>
> ---
> cmd/net.c | 35 ++++++++++++++++++++++++++++++
> net/net.c | 17 +++++++++++++--
> net/tftp.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++-------
> 3 files changed, 105 insertions(+), 10 deletions(-)
>
> diff --git a/cmd/net.c b/cmd/net.c
> index 3619c843d8..0f4f9a5625 100644
> --- a/cmd/net.c
> +++ b/cmd/net.c
> @@ -14,6 +14,7 @@
> #include <env.h>
> #include <image.h>
> #include <net.h>
> +#include <net6.h>
> #include <net/udp.h>
> #include <net/sntp.h>
>
> @@ -44,12 +45,22 @@ int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
> return ret;
> }
>
> +#if IS_ENABLED(CONFIG_IPV6)
> +U_BOOT_CMD(
> + tftpboot, 4, 1, do_tftpb,
> + "boot image via network using TFTP protocol\n"
> + "To use IPv6 add -ipv6 parameter or use IPv6 hostIPaddr framed "
> + "with [] brackets",
> + "[loadAddress] [[hostIPaddr:]bootfilename] [" USE_IP6_CMD_PARAM "]"
> +);
> +#else
> U_BOOT_CMD(
> tftpboot, 3, 1, do_tftpb,
> "boot image via network using TFTP protocol",
> "[loadAddress] [[hostIPaddr:]bootfilename]"
> );
> #endif
> +#endif
>
> #ifdef CONFIG_CMD_TFTPPUT
> static int do_tftpput(struct cmd_tbl *cmdtp, int flag, int argc,
> @@ -205,6 +216,17 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
> if (s != NULL)
> image_load_addr = hextoul(s, NULL);
>
> + if (IS_ENABLED(CONFIG_IPV6)) {
> + use_ip6 = false;
> +
> + /* IPv6 parameter has to be always *last* */
> + if (!strcmp(argv[argc - 1], USE_IP6_CMD_PARAM)) {
> + use_ip6 = true;
> + /* It is a hack not to break switch/case code */
> + --argc;
> + }
> + }
> +
> switch (argc) {
> case 1:
> /* refresh bootfile name from env */
> @@ -257,6 +279,19 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
> }
> bootstage_mark(BOOTSTAGE_ID_NET_START);
>
> + if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) {
> + char *s, *e;
> + size_t len;
> +
> + s = strchr(net_boot_file_name, '[');
> + e = strchr(net_boot_file_name, ']');
> + if (s && e) {
> + len = e - s;
> + if (!string_to_ip6(s + 1, len - 1, &net_server_ip6))
> + use_ip6 = true;
> + }
> + }
> +
> size = net_loop(proto);
> if (size < 0) {
> bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
> diff --git a/net/net.c b/net/net.c
> index f818170930..eaf78c4980 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -1381,7 +1381,14 @@ static int net_check_prereq(enum proto_t protocol)
> /* Fall through */
> case TFTPGET:
> case TFTPPUT:
> - if (net_server_ip.s_addr == 0 && !is_serverip_in_cmd()) {
> + if (IS_ENABLED(CONFIG_IPV6) && use_ip6) {
> + if (!memcmp(&net_server_ip6, &net_null_addr_ip6,
> + sizeof(struct in6_addr)) &&
> + !strchr(net_boot_file_name, '[')) {
> + puts("*** ERROR: `serverip6' not set\n");
> + return 1;
> + }
> + } else if (net_server_ip.s_addr == 0 && !is_serverip_in_cmd()) {
> puts("*** ERROR: `serverip' not set\n");
> return 1;
> }
> @@ -1394,7 +1401,13 @@ common:
> case NETCONS:
> case FASTBOOT:
> case TFTPSRV:
> - if (net_ip.s_addr == 0) {
> + if (IS_ENABLED(CONFIG_IPV6) && use_ip6) {
> + if (!memcmp(&net_link_local_ip6, &net_null_addr_ip6,
> + sizeof(struct in6_addr))) {
> + puts("*** ERROR: `ip6addr` not set\n");
> + return 1;
> + }
> + } else if (net_ip.s_addr == 0) {
> puts("*** ERROR: `ipaddr' not set\n");
> return 1;
> }
> diff --git a/net/tftp.c b/net/tftp.c
> index dea9c25ffd..a6b0ec57a4 100644
> --- a/net/tftp.c
> +++ b/net/tftp.c
> @@ -15,6 +15,7 @@
> #include <log.h>
> #include <mapmem.h>
> #include <net.h>
> +#include <net6.h>
> #include <asm/global_data.h>
> #include <net/tftp.h>
> #include "bootp.h"
> @@ -41,6 +42,7 @@ DECLARE_GLOBAL_DATA_PTR;
> static ulong timeout_ms = TIMEOUT;
> static int timeout_count_max = (CONFIG_NET_RETRY_COUNT * 2);
> static ulong time_start; /* Record time we started tftp */
> +static struct in6_addr tftp_remote_ip6;
>
> /*
> * These globals govern the timeout behavior when attempting a connection to a
> @@ -116,6 +118,7 @@ static int tftp_put_final_block_sent;
>
> /* default TFTP block size */
> #define TFTP_BLOCK_SIZE 512
> +#define TFTP_MTU_BLOCKSIZE6 (CONFIG_TFTP_BLOCKSIZE - 20)
> /* sequence number is 16 bit */
> #define TFTP_SEQUENCE_SIZE ((ulong)(1<<16))
>
> @@ -320,7 +323,11 @@ static void tftp_send(void)
> * We will always be sending some sort of packet, so
> * cobble together the packet headers now.
> */
> - pkt = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
> + if (IS_ENABLED(CONFIG_IPV6) && use_ip6)
> + pkt = net_tx_packet + net_eth_hdr_size() +
> + IP6_HDR_SIZE + UDP_HDR_SIZE;
> + else
> + pkt = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
>
> switch (tftp_state) {
> case STATE_SEND_RRQ:
> @@ -422,8 +429,14 @@ static void tftp_send(void)
> break;
> }
>
> - net_send_udp_packet(net_server_ethaddr, tftp_remote_ip,
> - tftp_remote_port, tftp_our_port, len);
> + if (IS_ENABLED(CONFIG_IPV6) && use_ip6)
> + net_send_udp_packet6(net_server_ethaddr,
> + &tftp_remote_ip6,
> + tftp_remote_port,
> + tftp_our_port, len);
> + else
> + net_send_udp_packet(net_server_ethaddr, tftp_remote_ip,
> + tftp_remote_port, tftp_our_port, len);
>
> if (err_pkt)
> net_set_state(NETLOOP_FAIL);
> @@ -750,6 +763,9 @@ void tftp_start(enum proto_t protocol)
> debug("TFTP blocksize = %i, TFTP windowsize = %d timeout = %ld ms\n",
> tftp_block_size_option, tftp_window_size_option, timeout_ms);
>
> + if (IS_ENABLED(CONFIG_IPV6))
> + tftp_remote_ip6 = net_server_ip6;
> +
> tftp_remote_ip = net_server_ip;
> if (!net_parse_bootfile(&tftp_remote_ip, tftp_filename, MAX_LEN)) {
> sprintf(default_filename, "%02X%02X%02X%02X.img",
> @@ -764,18 +780,49 @@ void tftp_start(enum proto_t protocol)
> printf("*** Warning: no boot file name; using '%s'\n",
> tftp_filename);
> }
> + if (IS_ENABLED(CONFIG_IPV6)) {
> + if (use_ip6) {
> + char *s, *e;
> + size_t len;
> +
> + s = strchr(net_boot_file_name, '[');
> + e = strchr(net_boot_file_name, ']');
> + len = e - s;
> + if (s && e) {
> + string_to_ip6(s + 1, len, &tftp_remote_ip6);
> + strlcpy(tftp_filename, e + 2, MAX_LEN);
> + } else {
> + strlcpy(tftp_filename, net_boot_file_name, MAX_LEN);
> + tftp_filename[MAX_LEN - 1] = 0;
> + }
> + }
> + }
>
> printf("Using %s device\n", eth_get_name());
> - printf("TFTP %s server %pI4; our IP address is %pI4",
> +
> + if (IS_ENABLED(CONFIG_IPV6) && use_ip6) {
> + printf("TFTP from server %pI6c; our IP address is %pI6c",
> + &tftp_remote_ip6, &net_ip6);
> +
> + if (tftp_block_size_option > TFTP_MTU_BLOCKSIZE6)
> + tftp_block_size_option = TFTP_MTU_BLOCKSIZE6;
> + } else {
> + printf("TFTP %s server %pI4; our IP address is %pI4",
> #ifdef CONFIG_CMD_TFTPPUT
> - protocol == TFTPPUT ? "to" : "from",
> + protocol == TFTPPUT ? "to" : "from",
> #else
> - "from",
> + "from",
> #endif
> - &tftp_remote_ip, &net_ip);
> + &tftp_remote_ip, &net_ip);
> + }
>
> /* Check if we need to send across this subnet */
> - if (net_gateway.s_addr && net_netmask.s_addr) {
> + if (IS_ENABLED(CONFIG_IPV6) && use_ip6) {
> + if (!ip6_addr_in_subnet(&net_ip6, &tftp_remote_ip6,
> + net_prefix_length))
> + printf("; sending through gateway %pI6c",
> + &net_gateway6);
> + } else if (net_gateway.s_addr && net_netmask.s_addr) {
> struct in_addr our_net;
> struct in_addr remote_net;
>
> --
> 2.25.1
>
Reviewed-by: Ramon Fried <rfried.dev at gmail.com>
More information about the U-Boot
mailing list