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.mitrofa...@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

Reply via email to