[U-Boot] [RFC PATCH v3 08/11] net: TFTP over IPv6

Simon Glass sjg at chromium.org
Mon Feb 6 15:32:49 UTC 2017


Hi Chris,

On 25 January 2017 at 01:56, Chris Packham <judge.packham at gmail.com> wrote:
> Add support for UDP/TFTP over IPv6. To support specifying an server IPv6
> address in the command square brackets must be used to separate the
> address from the filename. e.g
>   tftpboot6 [2001:db8::1]:zImage

Ick, but I suppose we are painted into a corner here. Perhaps we
should support a different separator like ',' and then that can be
used instead? Having separators inside [] makes it harder to find a
'real' separator since you need to parse the [].

>
> Signed-off-by: Chris Packham <judge.packham at gmail.com>
> ---
>
> Changes in v3: None
> Changes in v2:
> - Support parsing the server address from the command parameter.
>
>  cmd/Kconfig    |  9 +++++++++
>  cmd/net.c      | 13 ++++++++++++
>  include/net.h  |  2 +-
>  include/net6.h |  4 ++++
>  net/net.c      |  3 +++
>  net/net6.c     | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  net/tftp.c     | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  7 files changed, 152 insertions(+), 1 deletion(-)

Reviewed-by: Simon Glass <sjg at chromium.org>

>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 37126577bc65..473d354fcb85 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -504,6 +504,15 @@ config CMD_NET
>           bootp - boot image via network using BOOTP/TFTP protocol
>           tftpboot - boot image via network using TFTP protocol
>
> +config CMD_NET6
> +       bool "ipv6 commands"
> +       select NET
> +       select NET6
> +       default n
> +       help
> +         IPv6 network commands
> +         tftpboot6 - boot image via network using TFTP protocol
> +
>  config CMD_TFTPPUT
>         bool "tftp put"
>         help
> diff --git a/cmd/net.c b/cmd/net.c
> index 7f40f257c03c..e2c295eabb17 100644
> --- a/cmd/net.c
> +++ b/cmd/net.c
> @@ -42,6 +42,19 @@ U_BOOT_CMD(
>         "[loadAddress] [[hostIPaddr:]bootfilename]"
>  );
>
> +#ifdef CONFIG_CMD_NET6
> +int do_tftpb6(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       return netboot_common(TFTP6, cmdtp, argc, argv);
> +}
> +
> +U_BOOT_CMD(
> +       tftpboot6,      3,      1,      do_tftpb6,
> +       "boot image via network using TFTP protocol",
> +       "[loadAddress] [[hostIP6Addr]:][bootfilename]"
> +);
> +#endif
> +
>  #ifdef CONFIG_CMD_TFTPPUT
>  int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  {
> diff --git a/include/net.h b/include/net.h
> index be75c6c65c6b..6c968711c37f 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -546,7 +546,7 @@ extern int          net_restart_wrap;       /* Tried all network devices */
>
>  enum proto_t {
>         BOOTP, RARP, ARP, TFTPGET, DHCP, PING, PING6, DNS, NFS, CDP, NETCONS,
> -       SNTP, TFTPSRV, TFTPPUT, LINKLOCAL
> +       SNTP, TFTPSRV, TFTPPUT, TFTP6, LINKLOCAL
>  };
>
>  extern char    net_boot_file_name[1024];/* Boot File name */
> diff --git a/include/net6.h b/include/net6.h
> index ff97c39a6925..7ae177738e86 100644
> --- a/include/net6.h
> +++ b/include/net6.h
> @@ -246,6 +246,10 @@ void ping6_start(void);
>  void ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6,
>                           int len);
>
> +/* Transmit UDP packet using IPv6, performing neighbour discovery if needed */

Comment args and return value

> +int net_send_udp_packet6(uchar *ether, struct in6_addr *dest,
> +                               int dport, int sport, int len);
> +
>  /* handler for incoming IPv6 echo packet */
>  void net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6,
>                             int len);
> diff --git a/net/net.c b/net/net.c
> index 527c99f96f9f..567550ef09b6 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -454,6 +454,9 @@ restart:
>  #ifdef CONFIG_CMD_TFTPPUT
>                 case TFTPPUT:
>  #endif
> +#ifdef CONFIG_CMD_NET6
> +               case TFTP6:
> +#endif
>                         /* always use ARP to get server ethernet address */
>                         tftp_start(protocol);
>                         break;
> diff --git a/net/net6.c b/net/net6.c
> index 8f0c7214f8e1..5b8a003f1c4a 100644
> --- a/net/net6.c
> +++ b/net/net6.c
> @@ -342,6 +342,50 @@ ip6_add_hdr(uchar *xip, struct in6_addr *src, struct in6_addr *dest,
>         return sizeof(struct ip6_hdr);
>  }
>
> +int

Join with next line

> +net_send_udp_packet6(uchar *ether, struct in6_addr *dest, int dport, int sport, int len)
> +{
> +       uchar *pkt;
> +       struct udp_hdr *udp;
> +
> +       udp = (struct udp_hdr *)((uchar *)net_tx_packet + net_eth_hdr_size() + IP6_HDR_SIZE);
> +
> +       udp->udp_dst = htons(dport);
> +       udp->udp_src = htons(sport);
> +       udp->udp_len = htons(len + UDP_HDR_SIZE);
> +       /* checksum */
> +       udp->udp_xsum = 0;
> +       udp->udp_xsum = csum_ipv6_magic(&net_ip6, dest, len + UDP_HDR_SIZE,
> +               IPPROTO_UDP, csum_partial((__u8 *)udp, len + UDP_HDR_SIZE, 0));
> +
> +       /* if MAC address was not discovered yet, save the packet and do neighbour discovery */
> +       if (memcmp(ether, net_null_ethaddr, 6) == 0) {
> +               net_copy_ip6(&net_nd_sol_packet_ip6, dest);
> +               net_nd_packet_mac = ether;
> +
> +               pkt = net_nd_tx_packet;
> +               pkt += net_set_ether(pkt, net_nd_packet_mac, PROT_IP6);
> +               pkt += ip6_add_hdr(pkt, &net_ip6, dest, IPPROTO_UDP, 64, len + UDP_HDR_SIZE);
> +               memcpy(pkt, (uchar *)udp, len + UDP_HDR_SIZE);
> +
> +               /* size of the waiting packet */
> +               net_nd_tx_packet_size = (pkt - net_nd_tx_packet) + UDP_HDR_SIZE + len;
> +
> +               /* and do the neighbor solicitation */
> +               net_nd_try = 1;
> +               net_nd_timer_start = get_timer(0);
> +               ndisc_request();
> +               return 1;       /* waiting */

-EAGAIN?

> +       }
> +
> +       pkt = (uchar *)net_tx_packet;
> +       pkt += net_set_ether(pkt, ether, PROT_IP6);
> +       pkt += ip6_add_hdr(pkt, &net_ip6, dest, IPPROTO_UDP, 64, len + UDP_HDR_SIZE);
> +       (void) eth_send(net_tx_packet, (pkt - net_tx_packet) + UDP_HDR_SIZE + len);

Why swallow the error? Shouldn't you return it here?

> +
> +       return 0;       /* transmitted */
> +}
> +
>  void net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
>  {
>         struct in_addr zero_ip = {.s_addr = 0 };
> @@ -388,6 +432,26 @@ void net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
>                 }
>                 break;
>
> +       case IPPROTO_UDP:
> +               udp = (struct udp_hdr *)(((uchar *)ip6) + IP6_HDR_SIZE);
> +               csum = udp->udp_xsum;
> +               hlen = ntohs(ip6->payload_len);
> +               udp->udp_xsum = 0;
> +               /* checksum */
> +               udp->udp_xsum = csum_ipv6_magic(&ip6->saddr, &ip6->daddr,
> +                               hlen, IPPROTO_UDP, csum_partial((__u8 *)udp, hlen, 0));
> +               if (csum != udp->udp_xsum)
> +                       return;

Error?

> +
> +               /* IP header OK.  Pass the packet to the current handler. */
> +               net_get_udp_handler()((uchar *)ip6 + IP6_HDR_SIZE +
> +                                       UDP_HDR_SIZE,
> +                               ntohs(udp->udp_dst),
> +                               zero_ip,
> +                               ntohs(udp->udp_src),
> +                               ntohs(udp->udp_len) - 8);
> +               break;
> +
>         default:
>                 return;
>                 break;
> diff --git a/net/tftp.c b/net/tftp.c
> index ced45ec1f1f4..dbcefd2d4257 100644
> --- a/net/tftp.c
> +++ b/net/tftp.c
> @@ -11,6 +11,7 @@
>  #include <efi_loader.h>
>  #include <mapmem.h>
>  #include <net.h>
> +#include <net6.h>
>  #include <net/tftp.h>
>  #include "bootp.h"
>  #ifdef CONFIG_SYS_DIRECT_FLASH_TFTP
> @@ -67,6 +68,9 @@ enum {
>  };
>
>  static struct in_addr tftp_remote_ip;
> +#ifdef CONFIG_CMD_NET6
> +static struct in6_addr tftp_remote_ip6;
> +#endif
>  /* The UDP port at their end */
>  static int     tftp_remote_port;
>  /* The UDP port at our end */
> @@ -95,6 +99,10 @@ static int   tftp_put_final_block_sent;
>  #else
>  #define tftp_put_active        0
>  #endif
> +#ifdef CONFIG_CMD_NET6
> +/* 1 if using IPv6, else 0 */
> +static int      tftp6_active;
> +#endif
>
>  #define STATE_SEND_RRQ 1
>  #define STATE_DATA     2
> @@ -130,6 +138,8 @@ static char tftp_filename[MAX_LEN];
>  #else
>  #define TFTP_MTU_BLOCKSIZE 1468
>  #endif
> +/* IPv6 adds 20 bytes extra overhead */
> +#define TFTP_MTU_BLOCKSIZE6 (TFTP_MTU_BLOCKSIZE - 20)
>
>  static unsigned short tftp_block_size = TFTP_BLOCK_SIZE;
>  static unsigned short tftp_block_size_option = TFTP_MTU_BLOCKSIZE;
> @@ -342,6 +352,12 @@ static void tftp_send(void)
>          *      We will always be sending some sort of packet, so
>          *      cobble together the packet headers now.
>          */
> +#ifdef CONFIG_CMD_NET6
> +       if (tftp6_active)
> +               pkt = net_tx_packet + net_eth_hdr_size() +
> +                     IP6_HDR_SIZE + UDP_HDR_SIZE;
> +       else
> +#endif
>         pkt = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
>
>         switch (tftp_state) {
> @@ -441,6 +457,12 @@ static void tftp_send(void)
>                 break;
>         }
>
> +#ifdef CONFIG_CMD_NET6
> +       if (tftp6_active)
> +               net_send_udp_packet6(net_server_ethaddr, &tftp_remote_ip6,
> +                                    tftp_remote_port, tftp_our_port, len);
> +       else
> +#endif
>         net_send_udp_packet(net_server_ethaddr, tftp_remote_ip,
>                             tftp_remote_port, tftp_our_port, len);
>  }
> @@ -734,6 +756,10 @@ void tftp_start(enum proto_t protocol)
>         debug("TFTP blocksize = %i, timeout = %ld ms\n",
>               tftp_block_size_option, timeout_ms);
>
> +#ifdef CONFIG_CMD_NET6
> +       tftp6_active = (protocol == TFTP6);
> +       tftp_remote_ip6 = net_server_ip6;
> +#endif
>         tftp_remote_ip = net_server_ip;
>         if (net_boot_file_name[0] == '\0') {
>                 sprintf(default_filename, "%02X%02X%02X%02X.img",
> @@ -747,6 +773,20 @@ void tftp_start(enum proto_t protocol)
>
>                 printf("*** Warning: no boot file name; using '%s'\n",
>                        tftp_filename);
> +#ifdef CONFIG_CMD_NET6
> +       } else if (tftp6_active) {
> +               char *s, *e;
> +               s = strchr(net_boot_file_name, '[');
> +               e = strchr(net_boot_file_name, ']');

I don't expected [ or ] would appear in filenames, but they are not
actually illegal.

> +               if (s && e) {
> +                       *e++ = 0;
> +                       string_to_ip6(s + 1, &tftp_remote_ip6);
> +                       strncpy(tftp_filename, e + 1, MAX_LEN);
> +               } else {
> +                       strncpy(tftp_filename, net_boot_file_name, MAX_LEN);
> +                       tftp_filename[MAX_LEN - 1] = 0;
> +               }
> +#endif
>         } else {
>                 char *p = strchr(net_boot_file_name, ':');
>
> @@ -761,6 +801,15 @@ void tftp_start(enum proto_t protocol)
>         }
>
>         printf("Using %s device\n", eth_get_name());
> +#ifdef CONFIG_CMD_NET6
> +       if (tftp6_active) {
> +               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
> +#endif
>         printf("TFTP %s server %pI4; our IP address is %pI4",
>  #ifdef CONFIG_CMD_TFTPPUT
>                protocol == TFTPPUT ? "to" : "from",
> @@ -770,6 +819,15 @@ void tftp_start(enum proto_t protocol)
>                &tftp_remote_ip, &net_ip);
>
>         /* Check if we need to send across this subnet */
> +#ifdef CONFIG_CMD_NET6
> +       if (tftp6_active) {
> +               if (!ip6_addr_in_subnet(&net_ip6, &tftp_remote_ip6,
> +                                       net_prefix_length)) {
> +                       printf("; sending through gateway %pI6c",
> +                              &net_gateway6);
> +               }
> +       } else
> +#endif
>         if (net_gateway.s_addr && net_netmask.s_addr) {
>                 struct in_addr our_net;
>                 struct in_addr remote_net;
> --
> 2.11.0.24.ge6920cf
>

Regards,
Simon


More information about the U-Boot mailing list