Hi Chris, On Mon, Oct 12, 2015 at 2:43 AM, Chris Packham <judge.pack...@gmail.com> wrote: > Add support for UDP/TFTP over IPv6. > > Signed-off-by: Chris Packham <judge.pack...@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 ','? > 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@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot