
On Mon, Nov 9, 2015 at 1:38 AM, Chris Packham judge.packham@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
Signed-off-by: Chris Packham judge.packham@gmail.com
Changes in v2: None
Aren't the square brackets new?
common/Kconfig | 9 ++++++++ common/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(-)
diff --git a/common/Kconfig b/common/Kconfig index b1effc6..5914328 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -400,6 +400,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
Wouldn't ping6 be considered a command? Why is this not added in an earlier patch to allow for ping6?
It seems like ping6 would depend on CMD_NET6. Also, it seems like tftp6 should be behind its own CMD_TFTP6 token, since it surely must be optional. Maybe we want it to be enabled by default, but it should be possible to disable.
I think you'll need to update the documentation patch as a result.
config CMD_TFTPPUT bool "tftp put" help diff --git a/common/cmd_net.c b/common/cmd_net.c index 271f91d..47b56ee 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] [[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 6a9832c..69e6a17 100644 --- a/include/net.h +++ b/include/net.h @@ -525,7 +525,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 ff97c39..7ae1777 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 */ +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 ca24673..2b0d17e 100644 --- a/net/net.c +++ b/net/net.c @@ -453,6 +453,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 8f0c721..5b8a003 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 +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 */
}
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);
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;
/* 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 f2889fe..aa9e6e4 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 @@ -66,6 +67,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 */ @@ -94,6 +98,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 +137,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 +351,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) {
@@ -440,6 +456,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); } @@ -733,6 +755,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", @@ -746,6 +772,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, ']');
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, ':');
@@ -760,6 +800,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", @@ -769,6 +818,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);
This seems like it should be a debug() message, not a printf().
}
} 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