From patchwork Mon Oct 12 07:43:12 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Packham X-Patchwork-Id: 528924 X-Patchwork-Delegate: joe.hershberger@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id BE1941402A1 for ; Mon, 12 Oct 2015 18:44:42 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=UlrNy6nj; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 7DADD4B85E; Mon, 12 Oct 2015 09:44:41 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id TSg7LwIdRGlG; Mon, 12 Oct 2015 09:44:41 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 2B7724B7BE; Mon, 12 Oct 2015 09:44:41 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 5B6134B890 for ; Mon, 12 Oct 2015 09:44:20 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id nLY2VEQgvjas for ; Mon, 12 Oct 2015 09:44:20 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-pa0-f53.google.com (mail-pa0-f53.google.com [209.85.220.53]) by theia.denx.de (Postfix) with ESMTPS id 84D014B88F for ; Mon, 12 Oct 2015 09:44:15 +0200 (CEST) Received: by padhy16 with SMTP id hy16so147101731pad.1 for ; Mon, 12 Oct 2015 00:44:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ymr4ZGMRP3D4xQ7ZdT+7n0ntQBYkm+9IV3ftHn2fpfE=; b=UlrNy6njIS3vt+UtKfMYhw50OUHSSISxaMbMVsfQXckWTprVQ/18Q4t6hiqdNCrX4Q Y5aRwt48dmqK27l3IQFZIOZuSQZ9fOHYgVF30Ds7Xa427mggRpyUJ+oZvFsSKNB1ozfy 1LHP+vypxRDoKIOlIHh9f+4YGJh0KV5s/77zuqc9004Lyk5jLDtU9+w5UWrcO3a8WkbE 5WfkiEpkIXVQIkL89i/+0BB34avf3nPQCUkpU5Pw1GoBq3NVIIXRBzuhGs/hlNutyCvI cKTBVuJod2IDegQLAYVrC3iWJTon1qe4V0kx29RTY8+qTJwaKKwBoh1+V9vt2J8SxC6w lumw== X-Received: by 10.66.102.7 with SMTP id fk7mr32985585pab.119.1444635853787; Mon, 12 Oct 2015 00:44:13 -0700 (PDT) Received: from chrisp-dl.ws.atlnz.lc (2-163-36-202-static.alliedtelesis.co.nz. [202.36.163.2]) by smtp.gmail.com with ESMTPSA id cn4sm16451115pbc.94.2015.10.12.00.44.10 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 12 Oct 2015 00:44:13 -0700 (PDT) From: Chris Packham To: u-boot@lists.denx.de, Joe Hershberger Date: Mon, 12 Oct 2015 20:43:12 +1300 Message-Id: <1444635794-16285-7-git-send-email-judge.packham@gmail.com> X-Mailer: git-send-email 2.5.3 In-Reply-To: <1444635794-16285-1-git-send-email-judge.packham@gmail.com> References: <1444635794-16285-1-git-send-email-judge.packham@gmail.com> Cc: jp.tosoni@acksys.fr, hannah@marvell.com, Chris Packham , Angga Subject: [U-Boot] [RFC PATCH 6/8] net: TFTP over IPv6 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" Add support for UDP/TFTP over IPv6. Signed-off-by: Chris Packham --- 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). 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 #include #include +#include #include #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;