[PATCH 3/5] net: tftp: add IPv6 support for tftpboot

Viacheslav Mitrofanov v.v.mitrofanov at yadro.com
Fri Aug 19 10:09:49 CEST 2022


The command tftpboot uses IPv4 by default, to use IPv6 instead add -ipv6
as the last argument. All other tftpboot features and parameters are left
the same.

Signed-off-by: Viacheslav Mitrofanov <v.v.mitrofanov at yadro.com>
---
 cmd/net.c  | 21 ++++++++++++++++++
 net/net.c  | 17 +++++++++++++--
 net/tftp.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++-------
 3 files changed, 90 insertions(+), 10 deletions(-)

diff --git a/cmd/net.c b/cmd/net.c
index 3619c843d8..9225bddf6b 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,21 @@ 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"
+	"Use -ipv6 parameter to boot via IPv6",
+	"[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 +215,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 */
diff --git a/net/net.c b/net/net.c
index 3786217f05..d519173101 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..52ff1a846d 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,48 @@ 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;
+
+			s = strchr(net_boot_file_name, '[');
+			e = strchr(net_boot_file_name, ']');
+			if (s && e) {
+				*e++ = 0;
+				string_to_ip6(s + 1, &tftp_remote_ip6);
+				strlcpy(tftp_filename, e + 1, 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



More information about the U-Boot mailing list