On Tue, Nov 3, 2015 at 9:43 AM, Joe Hershberger <[email protected]> wrote: > Hi Chris, > > On Mon, Oct 12, 2015 at 2:43 AM, Chris Packham <[email protected]> > wrote: >> Add support for UDP/TFTP over IPv6. >> >> Signed-off-by: Chris Packham <[email protected]> >> --- >> 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 >> [email protected] >> http://lists.denx.de/mailman/listinfo/u-boot _______________________________________________ U-Boot mailing list [email protected] http://lists.denx.de/mailman/listinfo/u-boot

