[U-Boot] [RFC PATCH 6/8] net: TFTP over IPv6

Chris Packham judge.packham at gmail.com
Tue Nov 3 11:15:13 CET 2015


On Tue, Nov 3, 2015 at 9:43 AM, Joe Hershberger
<joe.hershberger at gmail.com> wrote:
> Hi Chris,
>
> On Mon, Oct 12, 2015 at 2:43 AM, Chris Packham <judge.packham at gmail.com> wrote:
>> Add support for UDP/TFTP over IPv6.
>>
>> Signed-off-by: Chris Packham <judge.packham at gmail.com>
>> ---
>> One problem with the [hostIpAddr:]fileName syntax is that IPv6 addresses
>> contains colons. So tftp_start() would be confused by 'tftpboot6
>> $loadaddr 2001:db8::1:zImage'. It is probably possible to change the
>> parsing to separate the host from the filename by parsing from the end
>> (i.e. use strrchr() instead of strchr()) but then there are error cases
>> that may not be handled correctly (e.g. omitting the filename).
>
> I think we should just change the filename separator for tftp6. How about ','?
>

The other strategy that is often used is to use square brackets to
separate the address from other data e.g. http://[2001:db8::1]:8080/.
Maybe that is a better (or at least more common) approach.

>>  common/cmd_net.c | 13 ++++++++++++
>>  include/net6.h   |  4 ++++
>>  net/net.c        |  3 +++
>>  net/net6.c       | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  net/tftp.c       | 37 ++++++++++++++++++++++++++++++++
>>  5 files changed, 121 insertions(+)
>>
>> diff --git a/common/cmd_net.c b/common/cmd_net.c
>> index 271f91d..3541599 100644
>> --- a/common/cmd_net.c
>> +++ b/common/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] [bootfilename]"
>> +);
>> +#endif
>> +
>>  #ifdef CONFIG_CMD_TFTPPUT
>>  int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>>  {
>> diff --git a/include/net6.h b/include/net6.h
>> index a0374df..df6d38e 100644
>> --- a/include/net6.h
>> +++ b/include/net6.h
>> @@ -264,6 +264,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 */
>> +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 349a18e..9e682b4 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 2315704..f5e272a 100644
>> --- a/net/net6.c
>> +++ b/net/net6.c
>> @@ -322,6 +322,50 @@ ip6_add_hdr(uchar *xip, struct in6_addr *src, struct in6_addr *dest,
>>         return sizeof(struct ip6_hdr);
>>  }
>>
>> +int
>> +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 + IP6_UDPHDR_SIZE);
>> +       /* checksum */
>> +       udp->udp_xsum = 0;
>> +       udp->udp_xsum = csum_ipv6_magic(&net_ip6, dest, len + IP6_UDPHDR_SIZE,
>> +               IPPROTO_UDP, csum_partial((__u8 *)udp, len + IP6_UDPHDR_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 + IP6_UDPHDR_SIZE);
>> +               memcpy(pkt, (uchar *)udp, len + IP6_UDPHDR_SIZE);
>> +
>> +               /* size of the waiting packet */
>> +               net_nd_tx_packet_size = (pkt - net_nd_tx_packet) + IP6_UDPHDR_SIZE + len;
>> +
>> +               /* and do the neighbor solicitation */
>> +               net_nd_try = 1;
>> +               net_nd_timer_start = get_timer(0);
>> +               ip6_NDISC_Request();
>> +               return 1;       /* waiting */
>> +       }
>> +
>> +       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 + IP6_UDPHDR_SIZE);
>> +       (void) eth_send(net_tx_packet, (pkt - net_tx_packet) + IP6_UDPHDR_SIZE + len);
>> +
>> +       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 };
>> @@ -368,6 +412,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;
>> +
>> +               /* IP header OK.  Pass the packet to the current handler. */
>> +               net_get_udp_handler()((uchar *)ip6 + IP6_HDR_SIZE +
>> +                                       IP6_UDPHDR_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 1a51131..1463bf2 100644
>> --- a/net/tftp.c
>> +++ b/net/tftp.c
>> @@ -10,6 +10,7 @@
>>  #include <command.h>
>>  #include <mapmem.h>
>>  #include <net.h>
>> +#include <net6.h>
>>  #include <net/tftp.h>
>>  #include "bootp.h"
>>  #ifdef CONFIG_SYS_DIRECT_FLASH_TFTP
>> @@ -94,6 +95,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
>> @@ -129,6 +134,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;
>> @@ -341,6 +348,11 @@ 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 + IP6_UDPHDR_SIZE;
>> +       else
>> +#endif
>>         pkt = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
>>
>>         switch (tftp_state) {
>> @@ -440,6 +452,12 @@ static void tftp_send(void)
>>                 break;
>>         }
>>
>> +#ifdef CONFIG_CMD_NET6
>> +       if (tftp6_active)
>> +               net_send_udp_packet6(net_server_ethaddr, &net_server_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);
>>  }
>> @@ -747,6 +765,16 @@ void tftp_start(enum proto_t protocol)
>>         }
>>
>>         printf("Using %s device\n", eth_get_name());
>> +#ifdef CONFIG_CMD_NET6
>> +       tftp6_active = (protocol == TFTP6);
>> +       if (tftp6_active) {
>> +               printf("TFTP from server %pI6c; our IP address is %pI6c",
>> +                      &net_server_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",
>> @@ -756,6 +784,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, &net_server_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.5.3
>>
>> _______________________________________________
>> U-Boot mailing list
>> U-Boot at lists.denx.de
>> http://lists.denx.de/mailman/listinfo/u-boot


More information about the U-Boot mailing list