[U-Boot] [PATCH] wget and enough TCP stack for fast netboot

Duncan Hare dh at synoia.com
Fri Sep 29 18:48:14 UTC 2017


Boot with udp is relatively slow on a local net, and very slow over a WAN.
TCP is a very effective protocol for fast file, or stream, transfers.
http (used by wget) is a very efficient protocol, there is one message to
retrieve the file, and acks from u-boot to server TCP thereafter.

The code was built & tested on a raspberry pi, LAN and WAN with
the Jan 2017 version of u-boot. This code is an update for the current
master, September 2017 version of u-boot, and cleaned up to pass
clearpatch standards, but not tested, because the current Sept
version of u-boot appears broken, rainbow screen of death, on raspberry pi.

This is a limited TCP implementation for the wget command only.
And all the code newly written, without viewing any copyrighted source.

Complied binary size: When using wget, tftp and nfs can be omitted
from the build. This has not been measured. When not using wget, the TCP
code is eliminted from the build.

All interfaces, funtion calls, in use are preserved. This reults in an ugly
"repurposing" of varaibles in the packet-in calls to wget. This requires
advice and guidence on the best implementation.

Kconfig is used in ./cmd and ./net to control wget and tcp respectively.
Makefile in ./net appears to have to be configured by hand.

Possible future additions include passing the TCP connection to the kernel
to complete boot, adding SSH to improve security, and sending device
MAC addresses or serial numbers (purportedly unique to a device)
for registration purposes.

Signed-off-by: Duncan Hare <Dh at Synoia.com>
---

 cmd/Kconfig   |   5 +
 cmd/net.c     |  13 +
 include/net.h | 241 +++++++++++++++-
 net/Kconfig   |   5 +
 net/Makefile  |   2 +-
 net/net.c     | 871 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 net/ping.c    |   9 +-
 net/wget.c    | 354 ++++++++++++++++++++++++
 net/wget.h    |   6 +
 9 files changed, 1365 insertions(+), 141 deletions(-)
 create mode 100644 net/wget.c
 create mode 100644 net/wget.h

diff --git a/cmd/Kconfig b/cmd/Kconfig
index d6d130edfa..a1596260bf 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1022,6 +1022,11 @@ config CMD_ETHSW
       operations such as enabling / disabling a port and
       viewing/maintaining the filtering database (FDB)
 
+config CMD_WGET
+    bool "wget"
+    help
+      Download a kernel, or other files, from a web server over TCP.
+
 endmenu
 
 menu "Misc commands"
diff --git a/cmd/net.c b/cmd/net.c
index d7c776aacf..f5c2d0f8ed 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -110,6 +110,19 @@ U_BOOT_CMD(
 );
 #endif
 
+#if defined(CONFIG_CMD_WGET)
+static int do_wget(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+    return netboot_common(WGET, cmdtp, argc, argv);
+}
+
+U_BOOT_CMD(
+    wget,    3,    1,    do_wget,
+    "boot image via network using HTTP protocol",
+    "[loadAddress] [[hostIPaddr:]bootfilename]"
+);
+#endif
+
 static void netboot_update_env(void)
 {
     char tmp[22];
diff --git a/include/net.h b/include/net.h
index 455b48f6c7..bbf199e9f6 100644
--- a/include/net.h
+++ b/include/net.h
@@ -24,7 +24,15 @@
  *    The number of receive packet buffers, and the required packet buffer
  *    alignment in memory.
  *
+ *    The nuber of buffers for TCP is used to calculate a static TCP window
+ *    size, becuse TCP window size is a promise to the sending TCP to be able
+ *    to buffer up to the window size of data.
+ *    When the sending TCP has a window size of outstanding unacknowledged
+ *    data, the sending TCP will stop sending.
  */
+#if defined(CONFIG_TCP)
+#define CONFIG_SYS_RX_ETH_BUFFER 50     /* For TCP */
+#endif
 
 #ifdef CONFIG_SYS_RX_ETH_BUFFER
 # define PKTBUFSRX    CONFIG_SYS_RX_ETH_BUFFER
@@ -47,7 +55,7 @@ struct in_addr {
     __be32 s_addr;
 };
 
-/**
+/*
  * An incoming packet handler.
  * @param pkt    pointer to the application packet
  * @param dport  destination UDP port
@@ -59,7 +67,7 @@ typedef void rxhand_f(uchar *pkt, unsigned dport,
               struct in_addr sip, unsigned sport,
               unsigned len);
 
-/**
+/*
  * An incoming ICMP packet handler.
  * @param type    ICMP type
  * @param code    ICMP code
@@ -308,7 +316,7 @@ struct ethernet_hdr {
     u8        et_dest[ARP_HLEN];    /* Destination node    */
     u8        et_src[ARP_HLEN];    /* Source node        */
     u16        et_protlen;        /* Protocol or length    */
-} __attribute__((packed));
+} __packed;
 
 /* Ethernet header size */
 #define ETHER_HDR_SIZE    (sizeof(struct ethernet_hdr))
@@ -326,7 +334,7 @@ struct e802_hdr {
     u8        et_snap2;
     u8        et_snap3;
     u16        et_prot;        /* 802 protocol        */
-} __attribute__((packed));
+} __packed;
 
 /* 802 + SNAP + ethernet header size */
 #define E802_HDR_SIZE    (sizeof(struct e802_hdr))
@@ -340,7 +348,7 @@ struct vlan_ethernet_hdr {
     u16        vet_vlan_type;        /* PROT_VLAN        */
     u16        vet_tag;        /* TAG of VLAN        */
     u16        vet_type;        /* protocol type    */
-} __attribute__((packed));
+} __packed;
 
 /* VLAN Ethernet header size */
 #define VLAN_ETHER_HDR_SIZE    (sizeof(struct vlan_ethernet_hdr))
@@ -353,6 +361,7 @@ struct vlan_ethernet_hdr {
 #define PROT_PPP_SES    0x8864        /* PPPoE session messages    */
 
 #define IPPROTO_ICMP     1    /* Internet Control Message Protocol    */
+#define IPPROTO_TCP     6    /* Transmission Control Protocol        */
 #define IPPROTO_UDP    17    /* User Datagram Protocol        */
 
 /*
@@ -369,7 +378,7 @@ struct ip_hdr {
     u16        ip_sum;        /* checksum            */
     struct in_addr    ip_src;        /* Source IP address        */
     struct in_addr    ip_dst;        /* Destination IP address    */
-} __attribute__((packed));
+} __packed;
 
 #define IP_OFFS        0x1fff /* ip offset *= 8 */
 #define IP_FLAGS    0xe000 /* first 3 bits */
@@ -397,11 +406,196 @@ struct ip_udp_hdr {
     u16        udp_dst;    /* UDP destination port        */
     u16        udp_len;    /* Length of UDP packet        */
     u16        udp_xsum;    /* Checksum            */
-} __attribute__((packed));
+} __packed;
 
 #define IP_UDP_HDR_SIZE        (sizeof(struct ip_udp_hdr))
 #define UDP_HDR_SIZE        (IP_UDP_HDR_SIZE - IP_HDR_SIZE)
 
+struct ip_tcp_hdr {
+    u8        ip_hl_v;    /* header length and version    */
+    u8        ip_tos;        /* type of service        */
+    u16        ip_len;        /* total length            */
+    u16        ip_id;        /* identification        */
+    u16        ip_off;        /* fragment offset field    */
+    u8        ip_ttl;        /* time to live            */
+    u8        ip_p;        /* protocol            */
+    u16        ip_sum;        /* checksum            */
+    struct in_addr    ip_src;        /* Source IP address        */
+    struct in_addr    ip_dst;        /* Destination IP address    */
+    u16        tcp_src;    /* TCP source port        */
+    u16        tcp_dst;    /* TCP destination port        */
+    u32        tcp_seq;    /* TCP sequence number        */
+    u32        tcp_ack;    /* TCP Acknowledgement number    */
+    u8        tcp_hlen;    /* 4 bits TCP header Length/4    */
+                    /* 4 bits Reserved        */
+                    /* 2 more bits reserved        */
+    u8        tcp_flags;    /* see defines            */
+    u16        tcp_win;    /* TCP windows size        */
+    u16        tcp_xsum;    /* Checksum            */
+    u16        tcp_ugr;    /* Pointer to urgent data    */
+} __packed;
+
+#define IP_TCP_HDR_SIZE        (sizeof(struct ip_tcp_hdr))
+#define TCP_HDR_SIZE        (IP_TCP_HDR_SIZE  - IP_HDR_SIZE)
+
+#define TCP_DATA    0x00    /* Data Packet - internal use only    */
+#define TCP_FIN        0x01    /* Finish flag                */
+#define TCP_SYN        0x02    /* Sybch (start) flag            */
+#define TCP_RST        0x04    /* reset flag                */
+#define TCP_PUSH    0x08    /* Push - Notify app            */
+#define TCP_ACK        0x10    /* Acknowledgement of data received    */
+#define TCP_URG        0x20    /* Urgent                */
+#define TCP_ECE        0x40    /* Congestion control            */
+#define TCP_CWR        0x80    /* Congestion Control            */
+
+/*
+ * TCP header options, Seq, MSS, and SACK
+ */
+
+#define TCP_O_END    0x00        /* End of option list        */
+#define TCP_1_NOP    0x01        /* Single padding NOP        */
+#define TCP_O_NOP    0x01010101    /* NOPs pad to 32 bit boundary    */
+#define TCP_O_MSS    0x02        /* MSS Size option        */
+#define TCP_O_SCL    0x03        /* Window Scale option        */
+#define TCP_P_SACK    0x04        /* SACK permitted        */
+#define TCP_V_SACK    0x05        /* SACK values            */
+#define TCP_O_TS    0x08        /* Timestanp option        */
+#define TCP_OPT_LEN_2    0x02
+#define TCP_OPT_LEN_3    0x03
+#define TCP_OPT_LEN_4    0x04
+#define TCP_OPT_LEN_6    0x06
+#define TCP_OPT_LEN_8    0x08
+#define TCP_OPT_LEN_A    0x0a        /* Timestamp Length        */
+
+/*
+ * Please reviw the warning in net.c about these two paraeters.
+ * They are part of a promise of RX buffer size to the sending TCP
+ */
+
+#define TCP_MSS        1460        /* Max segment size - 1460    */
+#define TCP_SCALE    0x01        /* Scale 1            */
+
+struct tcp_mss {            /* TCP Mex Segment size        */
+    u8    kind;            /* 0x02                */
+    u8    len;            /* 0x04                */
+    u16    mss;            /* 1460 - Max segment size    */
+} __packed;
+
+struct tcp_scale {            /* TCP Windows Scale        */
+    u8    kind;            /* 0x03                */
+    u8    len;            /* 0x03                */
+    u8    scale;            /* win shift fat fast networks    */
+} __packed;
+
+struct tcp_sack_p {            /* SACK permitted        */
+    u8    kind;            /* 0x04                */
+    u8    len;            /* Length            */
+} __packed;
+
+struct sack_edges {
+    u32    l;
+    u32    r;
+} __packed;
+
+#define TCP_SACK_HOLES    3
+
+struct tcp_sack_v {
+    u8    kind;            /* 0x05            */
+    u8    len;                /* Length        */
+    struct    sack_edges hole[TCP_SACK_HOLES]; /* L & R widow edges    */
+} __packed;
+
+struct tcp_TSopt {            /* TCP time stamps option    */
+    u8    kind;            /* 0x08                */
+    u8    len;            /* 0x0a                */
+    u32    TSsnd;            /* Sender timestamp        */
+    u32    TSrcv;            /* Receiver timestamp        */
+} __packed;
+
+#define TCP_TSOPT_SIZE    (sizeof(struct tcp_TSopt))
+
+/*
+ * ip tcp  structure with options
+ */
+
+struct ip_tcp_hdr_o {
+    struct    ip_tcp_hdr     hdr;
+    struct    tcp_mss        mss;
+     struct    tcp_scale     scale;
+    struct    tcp_sack_p    sack_p;
+    struct    tcp_TSopt    TSopt;
+    u8    end;
+} __packed;
+
+#define IP_TCP_O_SIZE        (sizeof(struct ip_tcp_hdr_o))
+
+struct ip_tcp_hdr_s {
+    struct    ip_tcp_hdr    hdr;
+    struct    tcp_TSopt    TSopt;
+    struct    tcp_sack_v    sack_v;
+    u8    end;
+} __packed;
+
+#define IP_TCP_SACK_SIZE    (sizeof(struct ip_tcp_hdr_s))
+
+/*
+ * TCP psuedo header definitions
+ */
+#define PSUEDO_PAD_SIZE    8
+
+struct psuedo_hdr {
+    u8 padding[PSUEDO_PAD_SIZE];    /* psuedo header size    */
+                    /* = ip_tcp hdr size    */
+    struct in_addr p_src;
+    struct in_addr p_dst;
+    u8      rsvd;
+    u8      p;
+    u16     len;
+} __packed;
+
+#define PSUEDO_HDR_SIZE    (sizeof(struct psuedo_hdr)) - PSUEDO_PAD_SIZE
+
+/*
+ * union for building IP/TCP packet.
+ * build Psuedo header in packed bufferfirst, calculate TCP checksum
+ * then build IP header in packe buffer.
+ */
+
+union tcp_build_pkt {
+    struct psuedo_hdr ph;
+    struct ip_tcp_hdr_o ip;
+    struct ip_tcp_hdr_s sack;
+    uchar  raw[1600];
+} __packed;
+
+/*
+ * TCP STATE MACHINE STATES FOR SOCKET
+ */
+
+enum TCP_STATE {
+    TCP_CLOSED,        /* Need to send SYN to connect            */
+    TCP_SYN_SENT,        /* Trying to connect, waiting for SYN ACK   */
+    TCP_ESTABLISHED,    /* server and client have open connection   */
+    TCP_CLOSE_WAIT,        /* Received FIN, passed to app for        */
+    TCP_CLOSING,        /* Received FIN, sent FIN, ACK wait for ACK */
+    TCP_FIN_WAIT_1,        /* Sendt FIN waiting for response        */
+    TCP_FIN_WAIT_2        /* Received ACK from FIN sent, wait for FIN */
+};
+
+enum TCP_STATE net_get_tcp_state(void);
+int net_find_in_buffer(uchar raw[], int payload_len, uchar field[],
+               int field_len);
+void net_print_buffer(uchar raw[], int pkt_len, int payload_len,
+              int hdr_len, bool hide);
+
+/*
+ *      TCP incoming packet handler
+ */
+
+typedef void rxhand_tcp(uchar *pkt, unsigned int dport,
+            struct in_addr sip, unsigned int sport,
+            unsigned int len, enum TCP_STATE tcp_state);
+
 /*
  *    Address Resolution Protocol (ARP) header.
  */
@@ -435,7 +629,7 @@ struct arp_hdr {
     u8        ar_tha[];    /* Target hardware address    */
     u8        ar_tpa[];    /* Target protocol address    */
 #endif /* 0 */
-} __attribute__((packed));
+} __packed;
 
 #define ARP_HDR_SIZE    (8+20)        /* Size assuming ethernet    */
 
@@ -470,7 +664,7 @@ struct icmp_hdr {
         } frag;
         u8 data[0];
     } un;
-} __attribute__((packed));
+} __packed;
 
 #define ICMP_HDR_SIZE        (sizeof(struct icmp_hdr))
 #define IP_ICMP_HDR_SIZE    (IP_HDR_SIZE + ICMP_HDR_SIZE)
@@ -538,7 +732,7 @@ extern int        net_restart_wrap;    /* Tried all network devices */
 
 enum proto_t {
     BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
-    TFTPSRV, TFTPPUT, LINKLOCAL
+    TFTPSRV, TFTPPUT, LINKLOCAL, WGET
 };
 
 extern char    net_boot_file_name[1024];/* Boot File name */
@@ -596,9 +790,22 @@ int net_set_ether(uchar *xet, const uchar *dest_ethaddr, uint prot);
 int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot);
 
 /* Set IP header */
-void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source);
+void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source,
+               u16  pkt_len, u8 prot);
+int net_set_tcp_header(uchar *pkt, int len, u8 action, u32 tcp_seq_num,
+               u32 tcp_ack_seq_num);
+
 void net_set_udp_header(uchar *pkt, struct in_addr dest, int dport,
-                int sport, int len);
+            int sport, int len);
+/* Set ports  */
+void net_set_ports(int server_port, int our_port);
+
+/* Print packet or messsage */
+void net_print_buffer(uchar raw[], int pkt_len, int payload_len,
+              int hdr_len, bool hide);
+/* Find string in buffer */
+int net_find_in_buffer(uchar raw[], int payload_len,
+               uchar field[], int field_len);
 
 /**
  * compute_ip_checksum() - Compute IP checksum
@@ -631,6 +838,8 @@ unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new_sum);
 int ip_checksum_ok(const void *addr, unsigned nbytes);
 
 /* Callbacks */
+rxhand_f *net_get_tcp_handler(void);    /* Get TCP RX packet handler */
+void net_set_tcp_handler(rxhand_f *);   /* Set TCP RX packet handler */
 rxhand_f *net_get_udp_handler(void);    /* Get UDP RX packet handler */
 void net_set_udp_handler(rxhand_f *);    /* Set UDP RX packet handler */
 rxhand_f *net_get_arp_handler(void);    /* Get ARP RX packet handler */
@@ -670,6 +879,10 @@ static inline void net_send_packet(uchar *pkt, int len)
  * @param sport Source UDP port
  * @param payload_len Length of data after the UDP header
  */
+
+int net_send_ip_packet(int payload_len, int proto, u8 action,
+               u32 tcp_seq_num, u32 tcp_ack_num);
+
 int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport,
             int sport, int payload_len);
 
@@ -678,8 +891,8 @@ void net_process_received_packet(uchar *in_packet, int len);
 
 #ifdef CONFIG_NETCONSOLE
 void nc_start(void);
-int nc_input_packet(uchar *pkt, struct in_addr src_ip, unsigned dest_port,
-    unsigned src_port, unsigned len);
+int nc_input_packet(uchar *pkt, struct in_addr src_ip, unsigned int dest_port,
+            unsigned int src_port, unsigned int len);
 #endif
 
 static __always_inline int eth_is_on_demand_init(void)
diff --git a/net/Kconfig b/net/Kconfig
index 414c5497c7..625ad291bb 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -45,4 +45,9 @@ config BOOTP_VCI_STRING
     default "U-Boot.arm" if ARM
     default "U-Boot"
 
+config TCP
+    bool "Include Subset TCP stack for wget"
+    help
+      TCP protocol support for wget.
+
 endif   # if NET
diff --git a/net/Makefile b/net/Makefile
index ae54eee5af..c788e2027b 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -25,7 +25,7 @@ obj-$(CONFIG_CMD_PING) += ping.o
 obj-$(CONFIG_CMD_RARP) += rarp.o
 obj-$(CONFIG_CMD_SNTP) += sntp.o
 obj-$(CONFIG_CMD_NET)  += tftp.o
-
+obj-$(CONFIG_CMD_WGET) += wget.o
 # Disable this warning as it is triggered by:
 # sprintf(buf, index ? "foo%d" : "foo", index)
 # and this is intentional usage.
diff --git a/net/net.c b/net/net.c
index 4259c9e321..f940cda8f9 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1,3 +1,5 @@
+/* */
+
 /*
  *    Copied from Linux Monitor (LiMon) - Networking.
  *
@@ -6,6 +8,7 @@
  *    Copyright 2000 Roland Borde
  *    Copyright 2000 Paolo Scaffardi
  *    Copyright 2000-2002 Wolfgang Denk, wd at denx.de
+ *    Copyright 2017 Duncan Hare, dh at synoia.com
  *    SPDX-License-Identifier:    GPL-2.0
  */
 
@@ -78,9 +81,18 @@
  *            - own IP address
  *    We want:    - network time
  *    Next step:    none
+ *
+ * HTTP/TCP Receiver:
+ *
+ *      Prequeisites:   - own ethernet adress
+ *                      - own IP address
+ *                      - Server IP address
+ *                      - HTP client
+ *                      - Bootfile path & name
+ *      We want:        - Load the Boot file
+ *      Next Step       HTTPS?
  */
-
-
+#define DEBUG_TCP_PKT 0        /* 1 to print debug messages, 0 to suppress */
 #include <common.h>
 #include <command.h>
 #include <console.h>
@@ -107,6 +119,7 @@
 #if defined(CONFIG_CMD_SNTP)
 #include "sntp.h"
 #endif
+#include "wget.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -137,12 +150,16 @@ u8 net_server_ethaddr[6];
 struct in_addr    net_ip;
 /* Server IP addr (0 = unknown) */
 struct in_addr    net_server_ip;
+/* Ports                */
+int dport;
+int sport;
+
 /* Current receive packet */
 uchar *net_rx_packet;
 /* Current rx packet length */
 int        net_rx_packet_len;
 /* IP packet ID */
-static unsigned    net_ip_id;
+static unsigned    int net_ip_id;
 /* Ethernet bcast address */
 const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 const u8 net_null_ethaddr[6];
@@ -178,9 +195,11 @@ struct in_addr    net_ntp_server;
 int        net_ntp_time_offset;
 #endif
 
-static uchar net_pkt_buf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
+static uchar net_pkt_buf[(PKTBUFSRX + 1) * PKTSIZE_ALIGN + PKTALIGN];
 /* Receive packets */
 uchar *net_rx_packets[PKTBUFSRX];
+/* Current TCP RX packet handler */
+static rxhand_f *tcp_packet_handler;
 /* Current UDP RX packet handler */
 static rxhand_f *udp_packet_handler;
 /* Current ARP RX packet handler */
@@ -198,6 +217,33 @@ static ulong    time_delta;
 /* THE transmit packet */
 uchar *net_tx_packet;
 
+#if defined(CONFIG_TCP)
+
+/* TCP sliding window  control  */
+/* used by us to request re-TX    */
+static u32 tcp_next_expected_seq_num;
+static struct tcp_sack_v tcp_lost;
+
+/* TCP option timestamp */
+static u32 loc_timestamp;
+static u32 rmt_timestamp;
+
+/* TCP connection state */
+static enum TCP_STATE tcp_state;
+
+/*
+ * An incoming TCP packet handler for the TCP protocol.
+ * There is also a dymanic function pointer for TCP based commads to
+ * receive incoming traffic after the TCP protocol code has done its work.
+ */
+
+void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int len);
+
+/* Current TCP RX packet handler */
+static rxhand_f *tcp_packet_handler;
+
+#endif
+
 static int net_check_prereq(enum proto_t protocol);
 
 static int net_try_count;
@@ -207,7 +253,7 @@ int __maybe_unused net_busy_flag;
 /**********************************************************************/
 
 static int on_bootfile(const char *name, const char *value, enum env_op op,
-    int flags)
+               int flags)
 {
     if (flags & H_PROGRAMMATIC)
         return 0;
@@ -224,10 +270,11 @@ static int on_bootfile(const char *name, const char *value, enum env_op op,
 
     return 0;
 }
+
 U_BOOT_ENV_CALLBACK(bootfile, on_bootfile);
 
 static int on_ipaddr(const char *name, const char *value, enum env_op op,
-    int flags)
+             int flags)
 {
     if (flags & H_PROGRAMMATIC)
         return 0;
@@ -236,10 +283,11 @@ static int on_ipaddr(const char *name, const char *value, enum env_op op,
 
     return 0;
 }
+
 U_BOOT_ENV_CALLBACK(ipaddr, on_ipaddr);
 
 static int on_gatewayip(const char *name, const char *value, enum env_op op,
-    int flags)
+            int flags)
 {
     if (flags & H_PROGRAMMATIC)
         return 0;
@@ -248,10 +296,11 @@ static int on_gatewayip(const char *name, const char *value, enum env_op op,
 
     return 0;
 }
+
 U_BOOT_ENV_CALLBACK(gatewayip, on_gatewayip);
 
 static int on_netmask(const char *name, const char *value, enum env_op op,
-    int flags)
+              int flags)
 {
     if (flags & H_PROGRAMMATIC)
         return 0;
@@ -260,10 +309,11 @@ static int on_netmask(const char *name, const char *value, enum env_op op,
 
     return 0;
 }
+
 U_BOOT_ENV_CALLBACK(netmask, on_netmask);
 
 static int on_serverip(const char *name, const char *value, enum env_op op,
-    int flags)
+               int flags)
 {
     if (flags & H_PROGRAMMATIC)
         return 0;
@@ -272,10 +322,11 @@ static int on_serverip(const char *name, const char *value, enum env_op op,
 
     return 0;
 }
+
 U_BOOT_ENV_CALLBACK(serverip, on_serverip);
 
 static int on_nvlan(const char *name, const char *value, enum env_op op,
-    int flags)
+            int flags)
 {
     if (flags & H_PROGRAMMATIC)
         return 0;
@@ -284,10 +335,11 @@ static int on_nvlan(const char *name, const char *value, enum env_op op,
 
     return 0;
 }
+
 U_BOOT_ENV_CALLBACK(nvlan, on_nvlan);
 
 static int on_vlan(const char *name, const char *value, enum env_op op,
-    int flags)
+           int flags)
 {
     if (flags & H_PROGRAMMATIC)
         return 0;
@@ -296,11 +348,12 @@ static int on_vlan(const char *name, const char *value, enum env_op op,
 
     return 0;
 }
+
 U_BOOT_ENV_CALLBACK(vlan, on_vlan);
 
 #if defined(CONFIG_CMD_DNS)
 static int on_dnsip(const char *name, const char *value, enum env_op op,
-    int flags)
+            int flags)
 {
     if (flags & H_PROGRAMMATIC)
         return 0;
@@ -309,6 +362,7 @@ static int on_dnsip(const char *name, const char *value, enum env_op op,
 
     return 0;
 }
+
 U_BOOT_ENV_CALLBACK(dnsip, on_dnsip);
 #endif
 
@@ -344,12 +398,11 @@ static void net_init_loop(void)
 {
     if (eth_get_dev())
         memcpy(net_ethaddr, eth_get_ethaddr(), 6);
-
-    return;
 }
 
 static void net_clear_handlers(void)
 {
+    net_set_tcp_handler(NULL);
     net_set_udp_handler(NULL);
     net_set_arp_handler(NULL);
     net_set_timeout_handler(0, NULL);
@@ -360,6 +413,12 @@ static void net_cleanup_loop(void)
     net_clear_handlers();
 }
 
+void net_set_ports(int server_port, int our_port)
+{
+    dport = server_port;
+    sport = our_port;
+}
+
 void net_init(void)
 {
     static int first_call = 1;
@@ -381,8 +440,10 @@ void net_init(void)
 
         /* Only need to setup buffer pointers once. */
         first_call = 0;
+#if defined(CONFIG_TCP)
+        tcp_state = TCP_CLOSED;
+#endif
     }
-
     net_init_loop();
 }
 
@@ -398,7 +459,7 @@ int net_loop(enum proto_t protocol)
     net_restarted = 0;
     net_dev_exists = 0;
     net_try_count = 1;
-    debug_cond(DEBUG_INT_STATE, "--- net_loop Entry\n");
+    debug_cond(DEBUG_INT_STATE, "%s--- Entry\n", __func__);
 
     bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
     net_init();
@@ -424,7 +485,7 @@ restart:
      *    here on, this code is a state machine driven by received
      *    packets and timer events.
      */
-    debug_cond(DEBUG_INT_STATE, "--- net_loop Init\n");
+    debug_cond(DEBUG_INT_STATE, "%s--- Init\n", __func__);
     net_init_loop();
 
     switch (net_check_prereq(protocol)) {
@@ -479,11 +540,16 @@ restart:
             ping_start();
             break;
 #endif
-#if defined(CONFIG_CMD_NFS)
+#if defined(CONFIG_CMD_NS)
         case NFS:
             nfs_start();
             break;
 #endif
+#if defined(CONFIG_CMD_WGET)
+        case WGET:
+            wget_start();
+            break;
+#endif
 #if defined(CONFIG_CMD_CDP)
         case CDP:
             cdp_start();
@@ -566,9 +632,9 @@ restart:
             eth_set_last_protocol(BOOTP);
 
             puts("\nAbort\n");
-            /* include a debug print as well incase the debug
-               messages are directed to stderr */
-            debug_cond(DEBUG_INT_STATE, "--- net_loop Abort!\n");
+            /* include a debug print as well incase the debug */
+            /*  messages are directed to stderr               */
+            debug_cond(DEBUG_INT_STATE, "%s--- Aborty\n", __func__);
             ret = -EINTR;
             goto done;
         }
@@ -597,7 +663,8 @@ restart:
                            CONFIG_LED_STATUS_ON);
 #endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
 #endif /* CONFIG_MII, ... */
-            debug_cond(DEBUG_INT_STATE, "--- net_loop timeout\n");
+            debug_cond(DEBUG_INT_STATE,
+                   "%s--- Timeout\n", __func__);
             x = time_handler;
             time_handler = (thand_f *)0;
             (*x)();
@@ -627,14 +694,15 @@ restart:
             eth_set_last_protocol(protocol);
 
             ret = net_boot_file_size;
-            debug_cond(DEBUG_INT_STATE, "--- net_loop Success!\n");
+            debug_cond(DEBUG_INT_STATE,
+                   "%s--- Success!\n", __func__);
             goto done;
 
         case NETLOOP_FAIL:
             net_cleanup_loop();
             /* Invalidate the last protocol */
             eth_set_last_protocol(BOOTP);
-            debug_cond(DEBUG_INT_STATE, "--- net_loop Fail!\n");
+            debug_cond(DEBUG_INT_STATE, "%s--- Fail\n", __func__);
             goto done;
 
         case NETLOOP_CONTINUE:
@@ -720,12 +788,21 @@ int net_start_again(void)
  *    Miscelaneous bits.
  */
 
-static void dummy_handler(uchar *pkt, unsigned dport,
-            struct in_addr sip, unsigned sport,
-            unsigned len)
+static void dummy_handler(uchar *pkt, unsigned int dport,
+              struct in_addr sip, unsigned int sport,
+              unsigned int len)
 {
 }
 
+void    net_set_tcp_handler(rxhand_f *f)
+{
+    debug_cond(DEBUG_INT_STATE, "--- net_loop TCP handler set (%p)\n", f);
+    if (!f)
+        tcp_packet_handler = dummy_handler;
+    else
+        tcp_packet_handler = f;
+}
+
 rxhand_f *net_get_udp_handler(void)
 {
     return udp_packet_handler;
@@ -734,7 +811,7 @@ rxhand_f *net_get_udp_handler(void)
 void net_set_udp_handler(rxhand_f *f)
 {
     debug_cond(DEBUG_INT_STATE, "--- net_loop UDP handler set (%p)\n", f);
-    if (f == NULL)
+    if (!f)
         udp_packet_handler = dummy_handler;
     else
         udp_packet_handler = f;
@@ -776,39 +853,61 @@ void net_set_timeout_handler(ulong iv, thand_f *f)
     }
 }
 
-int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport,
-        int payload_len)
+int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport,
+            int sport, int payload_len)
+{
+    net_set_ports(dport, sport);
+    return net_send_ip_packet(payload_len, IPPROTO_UDP,
+                  IPPROTO_UDP, 0, 0);
+}
+
+int net_send_ip_packet(int payload_len, int proto, u8 action,
+               u32 tcp_seq_num, u32 tcp_ack_num)
 {
     uchar *pkt;
     int eth_hdr_size;
     int pkt_hdr_size;
+    uchar *ether = net_server_ethaddr;
 
-    /* make sure the net_tx_packet is initialized (net_init() was called) */
+    /* make sure the net_tx_packet is initialized (net_init() was called)*/
     assert(net_tx_packet != NULL);
-    if (net_tx_packet == NULL)
+    if (!net_tx_packet)
         return -1;
 
     /* convert to new style broadcast */
-    if (dest.s_addr == 0)
-        dest.s_addr = 0xFFFFFFFF;
+    if (net_server_ip.s_addr == 0)
+        net_server_ip.s_addr = 0xFFFFFFFF;
 
     /* if broadcast, make the ether address a broadcast and don't do ARP */
-    if (dest.s_addr == 0xFFFFFFFF)
+    if (net_server_ip.s_addr == 0xFFFFFFFF)
         ether = (uchar *)net_bcast_ethaddr;
 
     pkt = (uchar *)net_tx_packet;
 
     eth_hdr_size = net_set_ether(pkt, ether, PROT_IP);
-    pkt += eth_hdr_size;
-    net_set_udp_header(pkt, dest, dport, sport, payload_len);
-    pkt_hdr_size = eth_hdr_size + IP_UDP_HDR_SIZE;
+#if defined(CONFIG_TCP)
+    if (proto == IPPROTO_UDP) {
+#endif
+        net_set_udp_header(pkt + eth_hdr_size, net_server_ip,
+                   dport, sport, payload_len);
+        pkt_hdr_size = IP_UDP_HDR_SIZE;
+        eth_hdr_size = eth_hdr_size + pkt_hdr_size;
 
+#if defined(CONFIG_TCP)
+    } else {
+        pkt_hdr_size = eth_hdr_size +
+        net_set_tcp_header(pkt + eth_hdr_size,
+                   payload_len, action,
+                   tcp_seq_num, tcp_ack_num);
+    }
+#endif
     /* if MAC address was not discovered yet, do an ARP request */
     if (memcmp(ether, net_null_ethaddr, 6) == 0) {
-        debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4\n", &dest);
+        debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4\n",
+               &net_server_ip);
 
         /* save the ip and eth addr for the packet to send after arp */
-        net_arp_wait_packet_ip = dest;
+        net_arp_wait_packet_ip = net_server_ip;
         arp_wait_packet_ethaddr = ether;
 
         /* size of the waiting packet */
@@ -821,7 +920,7 @@ int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport,
         return 1;    /* waiting */
     } else {
         debug_cond(DEBUG_DEV_PKT, "sending UDP to %pI4/%pM\n",
-               &dest, ether);
+               &net_server_ip, ether);
         net_send_packet(net_tx_packet, pkt_hdr_size + payload_len);
         return 0;    /* transmitted */
     }
@@ -868,7 +967,6 @@ static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
     thisfrag = payload + offset8;
     start = offset8 * 8;
     len = ntohs(ip->ip_len) - IP_HDR_SIZE;
-
     if (start + len > IP_MAXUDP) /* fragment extends too far */
         return NULL;
 
@@ -973,9 +1071,10 @@ static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
 }
 
 static inline struct ip_udp_hdr *net_defragment(struct ip_udp_hdr *ip,
-    int *lenp)
+                        int *lenp)
 {
     u16 ip_off = ntohs(ip->ip_off);
+
     if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
         return ip; /* not a fragment */
     return __net_defragment(ip, lenp);
@@ -984,9 +1083,10 @@ static inline struct ip_udp_hdr *net_defragment(struct ip_udp_hdr *ip,
 #else /* !CONFIG_IP_DEFRAG */
 
 static inline struct ip_udp_hdr *net_defragment(struct ip_udp_hdr *ip,
-    int *lenp)
+                        int *lenp)
 {
     u16 ip_off = ntohs(ip->ip_off);
+
     if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
         return ip; /* not a fragment */
     return NULL;
@@ -1000,7 +1100,7 @@ static inline struct ip_udp_hdr *net_defragment(struct ip_udp_hdr *ip,
  * @parma ip    IP packet containing the ICMP
  */
 static void receive_icmp(struct ip_udp_hdr *ip, int len,
-            struct in_addr src_ip, struct ethernet_hdr *et)
+             struct in_addr src_ip, struct ethernet_hdr *et)
 {
     struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src;
 
@@ -1157,9 +1257,6 @@ void net_process_received_packet(uchar *in_packet, int len)
         /* Can't deal with anything except IPv4 */
         if ((ip->ip_hl_v & 0xf0) != 0x40)
             return;
-        /* Can't deal with IP options (headers != 20 bytes) */
-        if ((ip->ip_hl_v & 0x0f) > 0x05)
-            return;
         /* Check the Checksum of the header */
         if (!ip_checksum_ok((uchar *)ip, IP_HDR_SIZE)) {
             debug("checksum bad\n");
@@ -1210,70 +1307,81 @@ void net_process_received_packet(uchar *in_packet, int len)
             return;
         } else if (ip->ip_p != IPPROTO_UDP) {    /* Only UDP packets */
             return;
-        }
-
-        debug_cond(DEBUG_DEV_PKT,
-               "received UDP (to=%pI4, from=%pI4, len=%d)\n",
-               &dst_ip, &src_ip, len);
+        } else if (ip->ip_p == IPPROTO_UDP) {
+            debug_cond(DEBUG_DEV_PKT,
+                   "received UDP (to=%pI4, from=%pI4, len=%d)\n",
+                   &dst_ip, &src_ip, len);
 
 #ifdef CONFIG_UDP_CHECKSUM
-        if (ip->udp_xsum != 0) {
-            ulong   xsum;
-            ushort *sumptr;
-            ushort  sumlen;
-
-            xsum  = ip->ip_p;
-            xsum += (ntohs(ip->udp_len));
-            xsum += (ntohl(ip->ip_src.s_addr) >> 16) & 0x0000ffff;
-            xsum += (ntohl(ip->ip_src.s_addr) >>  0) & 0x0000ffff;
-            xsum += (ntohl(ip->ip_dst.s_addr) >> 16) & 0x0000ffff;
-            xsum += (ntohl(ip->ip_dst.s_addr) >>  0) & 0x0000ffff;
-
-            sumlen = ntohs(ip->udp_len);
-            sumptr = (ushort *)&(ip->udp_src);
-
-            while (sumlen > 1) {
-                ushort sumdata;
-
-                sumdata = *sumptr++;
-                xsum += ntohs(sumdata);
-                sumlen -= 2;
-            }
-            if (sumlen > 0) {
-                ushort sumdata;
-
-                sumdata = *(unsigned char *)sumptr;
-                sumdata = (sumdata << 8) & 0xff00;
-                xsum += sumdata;
-            }
-            while ((xsum >> 16) != 0) {
-                xsum = (xsum & 0x0000ffff) +
+#define XFF 0x0000ffff
+            if (ip->udp_xsum != 0) {
+                ulong   xsum;
+                ushort *sumptr;
+                ushort  sumlen;
+
+                xsum  = ip->ip_p;
+                xsum += (ntohs(ip->udp_len));
+                xsum += (ntohl(ip->ip_src.s_addr) >> 16) & XFF;
+                xsum += (ntohl(ip->ip_src.s_addr) >>  0) & XFF;
+                xsum += (ntohl(ip->ip_dst.s_addr) >> 16) & XFF;
+                xsum += (ntohl(ip->ip_dst.s_addr) >>  0) & XFF;
+
+                sumlen = ntohs(ip->udp_len);
+                sumptr = (ushort *)&ip->udp_src;
+
+                while (sumlen > 1) {
+                    ushort sumdata;
+
+                    sumdata = *sumptr++;
+                    xsum += ntohs(sumdata);
+                    sumlen -= 2;
+                }
+                if (sumlen > 0) {
+                    ushort sumdata;
+
+                    sumdata = *(unsigned char *)sumptr;
+                    sumdata = (sumdata << 8) & 0xff00;
+                    xsum += sumdata;
+                }
+                while ((xsum >> 16) != 0) {
+                    xsum = (xsum & 0x0000ffff) +
                        ((xsum >> 16) & 0x0000ffff);
+                }
+                if ((xsum != 0x00000000) && (xsum != XFF)) {
+                    printf(" UDP bad xsum %08lx %08x\n",
+                           xsum, ntohs(ip->udp_xsum));
+                    return;
+                }
             }
-            if ((xsum != 0x00000000) && (xsum != 0x0000ffff)) {
-                printf(" UDP wrong checksum %08lx %08x\n",
-                       xsum, ntohs(ip->udp_xsum));
-                return;
-            }
-        }
 #endif
 
 #if defined(CONFIG_NETCONSOLE) && !defined(CONFIG_SPL_BUILD)
-        nc_input_packet((uchar *)ip + IP_UDP_HDR_SIZE,
-                src_ip,
-                ntohs(ip->udp_dst),
-                ntohs(ip->udp_src),
-                ntohs(ip->udp_len) - UDP_HDR_SIZE);
+            nc_input_packet((uchar *)ip + IP_UDP_HDR_SIZE,
+                    src_ip,
+                    ntohs(ip->udp_dst),
+                    ntohs(ip->udp_src),
+                    ntohs(ip->udp_len) - UDP_HDR_SIZE);
+#endif
+            /*
+             * IP header OK.  Pass packet to the current handler.
+             */
+            (*udp_packet_handler)((uchar *)ip + IP_UDP_HDR_SIZE,
+                          ntohs(ip->udp_dst),
+                          src_ip,
+                          ntohs(ip->udp_src),
+                          ntohs(ip->udp_len)
+                          -  UDP_HDR_SIZE);
+        }
+#if defined(CONFIG_TCP)
+        else if (ip->ip_p == IPPROTO_TCP) {   /* Only TCP packets */
+
+            debug_cond(DEBUG_DEV_PKT,
+                   "TCP PH (to=%pI4, from=%pI4, len=%d)\n",
+                   &dst_ip, &src_ip, len);
+
+            rxhand_tcp_f((union tcp_build_pkt *)ip, len);
+        }
 #endif
-        /*
-         * IP header OK.  Pass the packet to the current handler.
-         */
-        (*udp_packet_handler)((uchar *)ip + IP_UDP_HDR_SIZE,
-                      ntohs(ip->udp_dst),
-                      src_ip,
-                      ntohs(ip->udp_src),
-                      ntohs(ip->udp_len) - UDP_HDR_SIZE);
-        break;
     }
 }
 
@@ -1363,10 +1471,10 @@ common:
     }
     return 0;        /* OK */
 }
+
 /**********************************************************************/
 
-int
-net_eth_hdr_size(void)
+int net_eth_hdr_size(void)
 {
     ushort myvlanid;
 
@@ -1421,12 +1529,14 @@ int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot)
     } else {
         /* 802.2 + SNAP */
         struct e802_hdr *et802 = (struct e802_hdr *)et;
+
         et802->et_prot = htons(prot);
         return E802_HDR_SIZE;
     }
 }
 
-void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source)
+void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source,
+               u16  pkt_len, u8 prot)
 {
     struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt;
 
@@ -1436,19 +1546,21 @@ void net_set_ip_header(uchar *pkt, struct in_addr dest, struct in_addr source)
     /* IP_HDR_SIZE / 4 (not including UDP) */
     ip->ip_hl_v  = 0x45;
     ip->ip_tos   = 0;
-    ip->ip_len   = htons(IP_HDR_SIZE);
+    ip->ip_len   = htons(pkt_len);
     ip->ip_id    = htons(net_ip_id++);
     ip->ip_off   = htons(IP_FLAGS_DFRAG);    /* Don't fragment */
     ip->ip_ttl   = 255;
+    ip->ip_p     = prot;
     ip->ip_sum   = 0;
     /* already in network byte order */
     net_copy_ip((void *)&ip->ip_src, &source);
     /* already in network byte order */
     net_copy_ip((void *)&ip->ip_dst, &dest);
+    ip->ip_sum  = compute_ip_checksum(ip, IP_HDR_SIZE);
 }
 
-void net_set_udp_header(uchar *pkt, struct in_addr dest, int dport, int sport,
-            int len)
+void net_set_udp_header(uchar *pkt, struct in_addr dest,
+            int dport, int sport, int len)
 {
     struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt;
 
@@ -1460,10 +1572,8 @@ void net_set_udp_header(uchar *pkt, struct in_addr dest, int dport, int sport,
     if (len & 1)
         pkt[IP_UDP_HDR_SIZE + len] = 0;
 
-    net_set_ip_header(pkt, dest, net_ip);
-    ip->ip_len   = htons(IP_UDP_HDR_SIZE + len);
-    ip->ip_p     = IPPROTO_UDP;
-    ip->ip_sum   = compute_ip_checksum(ip, IP_HDR_SIZE);
+    net_set_ip_header(pkt, dest, net_ip, IP_UDP_HDR_SIZE + len,
+              IPPROTO_UDP);
 
     ip->udp_src  = htons(sport);
     ip->udp_dst  = htons(dport);
@@ -1485,7 +1595,8 @@ void copy_filename(char *dst, const char *src, int size)
 
 #if    defined(CONFIG_CMD_NFS)        || \
     defined(CONFIG_CMD_SNTP)    || \
-    defined(CONFIG_CMD_DNS)
+    defined(CONFIG_CMD_DNS)        || \
+    defined(CONFIG_CMD_WGET)
 /*
  * make port a little random (1024-17407)
  * This keeps the math somewhat trivial to compute, and seems to work with
@@ -1501,10 +1612,10 @@ void ip_to_string(struct in_addr x, char *s)
 {
     x.s_addr = ntohl(x.s_addr);
     sprintf(s, "%d.%d.%d.%d",
-        (int) ((x.s_addr >> 24) & 0xff),
-        (int) ((x.s_addr >> 16) & 0xff),
-        (int) ((x.s_addr >> 8) & 0xff),
-        (int) ((x.s_addr >> 0) & 0xff)
+        (int)((x.s_addr >> 24) & 0xff),
+        (int)((x.s_addr >> 16) & 0xff),
+        (int)((x.s_addr >> 8) & 0xff),
+        (int)((x.s_addr >> 0) & 0xff)
     );
 }
 
@@ -1540,3 +1651,525 @@ ushort env_get_vlan(char *var)
 {
     return string_to_vlan(env_get(var));
 }
+
+/*
+ * TCP module
+ */
+
+#if defined(CONFIG_TCP)
+
+enum TCP_STATE net_get_tcp_state(void)
+{
+    return tcp_state;
+}
+
+void net_print_buffer(uchar raw[], int pkt_len, int payload_len,
+              int hdr_len, bool hide)
+{
+    int i;
+
+    for (i = pkt_len - payload_len; i < pkt_len; i++) {
+        if (i <= hdr_len)
+            printf("%02X", raw[i]);
+        else if ((raw[i] > 0x19) && (raw[i] < 0x7f))
+            putc(raw[i]);
+        else if (hide == 0)
+            putc(raw[i]);
+        else
+            printf("%02X", raw[i]);
+    }
+    printf("%s", "\n");
+}
+
+int net_find_in_buffer(uchar raw[], int payload_len, uchar field[],
+               int field_len)
+{
+    int i, j;
+
+    for (i = 0; i < payload_len; i++) {
+        if (raw[i] == field[0]) {
+            for (j = 1; j < field_len; j++) {
+                if (raw[i + j] != field[j])
+                    break;
+            if (j == field_len)
+                return i;
+            }
+        }
+    }
+    return 0;
+}
+
+u16 net_set_psuedo_header(uchar *pkt, struct in_addr src, struct in_addr dest,
+              int tcp_len, int pkt_len)
+{
+    union tcp_build_pkt *b = (union tcp_build_pkt *)pkt;
+    int checksum_len;
+
+    /*
+     * Psuedo header
+     *
+     * Zero the byte after the last byte so that the header checksum
+     * will always work.
+     */
+
+    pkt[pkt_len] = 0x00;
+
+    net_copy_ip((void *)&b->ph.p_src, &src);
+    net_copy_ip((void *)&b->ph.p_dst, &dest);
+    b->ph.rsvd    = 0x00;
+    b->ph.p        = IPPROTO_TCP;
+    b->ph.len    = htons(tcp_len);
+    checksum_len    = tcp_len + PSUEDO_HDR_SIZE;
+
+        debug_cond(DEBUG_DEV_PKT,
+               "TCP Psuedo  Header  (to=%pI4, from=%pI4, Len=%d)\n",
+               &b->ph.p_dst, &b->ph.p_src, checksum_len);
+
+    return compute_ip_checksum(pkt + PSUEDO_PAD_SIZE, checksum_len);
+}
+
+int net_set_ack_options(union tcp_build_pkt *b)
+{
+    b->sack.hdr.tcp_hlen  = (TCP_HDR_SIZE >> 2) << 4;
+
+    b->sack.TSopt.kind        = TCP_O_TS;
+    b->sack.TSopt.len        = TCP_OPT_LEN_A;
+    b->sack.TSopt.TSsnd        = htons(loc_timestamp);
+    b->sack.TSopt.TSrcv        = rmt_timestamp;
+    b->sack.sack_v.kind             = 0x01;
+    b->sack.sack_v.len        = 0x00;
+
+    if (tcp_lost.len  > 0) {
+        b->sack.sack_v.len              = tcp_lost.len;
+        b->sack.sack_v.kind        = TCP_V_SACK;
+        b->sack.sack_v.hole[0].l    = htonl(tcp_lost.hole[1].l);
+        b->sack.sack_v.hole[0].r    = htonl(tcp_lost.hole[1].r);
+
+        /*
+         * These fields are initialized with NOPs to
+         * provide TCP header alignment padding
+         */
+
+        b->sack.sack_v.hole[1].l    = htonl(tcp_lost.hole[1].l);
+        b->sack.sack_v.hole[1].r    = htonl(tcp_lost.hole[1].r);
+        b->sack.sack_v.hole[2].l    = htonl(tcp_lost.hole[2].l);
+        b->sack.sack_v.hole[2].r    = htonl(tcp_lost.hole[2].r);
+
+        tcp_lost.len            = 0;
+    }
+    b->sack.hdr.tcp_hlen = (((TCP_HDR_SIZE + TCP_TSOPT_SIZE
+                + tcp_lost.len + 3)  >> 2) << 4);
+
+    return b->sack.hdr.tcp_hlen >> 2;
+}
+
+void net_set_syn_options(union tcp_build_pkt *b)
+{
+    tcp_lost.len        = 0;
+    b->ip.hdr.tcp_hlen      = 0xa0;
+
+    b->ip.mss.kind          = TCP_O_MSS;
+    b->ip.mss.len           = TCP_OPT_LEN_4;
+    b->ip.mss.mss           = htons(TCP_MSS);
+    b->ip.scale.kind        = TCP_O_SCL;
+    b->ip.scale.scale       = TCP_SCALE;
+    b->ip.scale.len         = TCP_OPT_LEN_3;
+    b->ip.sack_p.kind       = TCP_P_SACK;
+    b->ip.sack_p.len        = TCP_OPT_LEN_2;
+    b->ip.TSopt.kind        = TCP_O_TS;
+    b->ip.TSopt.len         = TCP_OPT_LEN_A;
+    loc_timestamp           = get_ticks() % 3072;
+    rmt_timestamp           = 0x00000000;
+    b->ip.TSopt.TSsnd    = 0;
+    b->ip.TSopt.TSrcv       = 0x00000000;
+    b->ip.end               = TCP_O_END;
+}
+
+int net_set_tcp_header(uchar *pkt, int payload_len, u8 action,
+               u32 tcp_seq_num, u32 tcp_ack_num)
+{
+    union tcp_build_pkt *b = (union tcp_build_pkt *)pkt;
+    int    pkt_hdr_len;
+    int    pkt_len;
+    int    tcp_len;
+
+    b->ip.hdr.tcp_flags    = action;
+    pkt_hdr_len        = IP_TCP_HDR_SIZE;
+    b->ip.hdr.tcp_hlen      = 0x50;        /* Header is 5 32 bit words  */
+                        /* 4 bits TCP header Length/4*/
+                        /* 4 bits Reserved           */
+                        /* For options             */
+    switch (action) {
+    case TCP_SYN:
+        debug_cond(DEBUG_TCP_PKT,
+               "TCP Hdr:SYN (%pI4, %pI4, sq=%d, ak=%d)\n",
+               &net_server_ip, &net_ip,
+               tcp_seq_num, tcp_ack_num);
+
+        net_set_syn_options(b);
+        tcp_seq_num = 0;
+        tcp_ack_num = 0;
+        pkt_hdr_len = IP_TCP_O_SIZE;
+        if (tcp_state == TCP_SYN_SENT) {  /* Too many sins */
+            action    = TCP_FIN;
+            tcp_state = TCP_FIN_WAIT_1;
+        } else {
+            tcp_state = TCP_SYN_SENT;
+        }
+    break;
+    case TCP_ACK:
+        pkt_hdr_len         = IP_HDR_SIZE + net_set_ack_options(b);
+        b->ip.hdr.tcp_flags = action;
+        debug_cond(DEBUG_TCP_PKT,
+               "TCP Hdr:ACK (%pI4, %pI4, s=%d, a=%d, A=%x)\n",
+               &net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num,
+               b->ip.hdr.tcp_flags);
+    break;
+    case TCP_FIN:
+        debug_cond(DEBUG_TCP_PKT,
+               "TCP Hdr:FIN  (%pI4, %pI4, s=%d, a=%d)\n",
+               &net_server_ip, &net_ip, tcp_seq_num, tcp_ack_num);
+        payload_len = 0;
+        pkt_hdr_len = IP_TCP_HDR_SIZE;
+        tcp_state   = TCP_FIN_WAIT_1;
+        tcp_seq_num++;
+    break;
+    case (TCP_FIN | TCP_ACK):                       /* Fall thru */
+    case (TCP_FIN | TCP_ACK | TCP_PUSH):            /* Fall thru */
+        if (tcp_state == TCP_CLOSE_WAIT)
+            tcp_state = TCP_CLOSING;
+    default:
+        pkt_hdr_len         = IP_HDR_SIZE + net_set_ack_options(b);
+        b->ip.hdr.tcp_flags = action | TCP_PUSH | TCP_ACK;
+        debug_cond(DEBUG_TCP_PKT,
+               "TCP Hdr:dft  (%pI4, %pI4, s=%d, a=%d, A=%x)\n",
+               &net_server_ip, &net_ip,
+               tcp_seq_num, tcp_ack_num, b->ip.hdr.tcp_flags);
+    break;
+    }
+
+    pkt_len    = pkt_hdr_len + payload_len;
+    tcp_len    = pkt_len - IP_HDR_SIZE;
+
+    /*
+     * TCP Header
+     */
+    b->ip.hdr.tcp_ack       = htonl(tcp_ack_num);
+    b->ip.hdr.tcp_src    = htons(sport);
+    b->ip.hdr.tcp_dst    = htons(dport);
+    b->ip.hdr.tcp_seq    = htonl(tcp_seq_num);
+    tcp_seq_num        = tcp_seq_num + payload_len;
+
+    /*
+     * TCP window size - TCP header variable tcp_win.
+     * Change tcp_win only if you have an understanding of network
+     * overruun, congestion, TCP segment sizes, TCP windows, TCP scale,
+     * queuing theory  and packet buffering. If there are too few buffers,
+     * there will be data loss, recovery may work or the sending TCP,
+     * the server, could abort the stream transmission.
+     * MSS is governed by maximum Ethernet frame langth.
+     * The number of buffers is governed by the desire to have a queue of
+     * full buffers to be processed at the destination to maximize
+     * throughput. Temporary memory use for the boot phase on modern
+     * SOCs is may not be considered a constraint to buffer space, if
+     * it is, thEn the u-boot tftp or nfs kernel netboot should be
+     * considered.
+     */
+
+    b->ip.hdr.tcp_win    = htons(PKTBUFSRX * TCP_MSS >> TCP_SCALE);
+
+    b->ip.hdr.tcp_xsum    = 0x0000;
+    b->ip.hdr.tcp_ugr    = 0x0000;
+
+    b->ip.hdr.tcp_xsum = net_set_psuedo_header(pkt, net_ip, net_server_ip,
+                           tcp_len, pkt_len);
+
+    /*
+     * IP Header
+     */
+
+    net_set_ip_header((uchar *)&b->ip, net_server_ip, net_ip,
+              pkt_len, IPPROTO_TCP);
+
+    return pkt_hdr_len;
+}
+
+void tcp_hole_create(u32 tcp_left, u32 tcp_right)
+{
+    debug_cond(DEBUG_TCP_PKT, "Hole Created Left=%d\n", tcp_left);
+
+    tcp_lost.len            = tcp_lost.len + TCP_OPT_LEN_A;
+    tcp_lost.hole[0].l      = tcp_left;
+    tcp_lost.hole[0].l      = tcp_right;
+
+    tcp_lost.hole[1].l      = TCP_O_NOP;
+    tcp_lost.hole[1].r      = TCP_O_NOP;
+    tcp_lost.hole[2].l      = TCP_O_NOP;
+    tcp_lost.hole[2].r      = TCP_O_NOP;
+}
+
+void tcp_parse_options(uchar *o, int o_len)
+{
+    struct tcp_TSopt  *tsopt;
+    uchar *p = o;
+
+    for (p = o; p < (o + o_len); (*p = *o + o_len)) {
+        if (*p == TCP_O_NOP)
+            p++;
+        switch (*p) {
+        case TCP_O_END:
+            return;
+        case TCP_O_MSS:
+        break;
+        case TCP_O_SCL:
+        break;
+        case TCP_P_SACK:
+        break;
+        case TCP_V_SACK:
+        break;
+        case TCP_O_TS:
+            tsopt = (struct tcp_TSopt *)p;
+            rmt_timestamp = tsopt->TSsnd;
+            return;
+        break;
+        }
+    }
+}
+
+u8 tcp_state_machine(u8 tcp_flags, u32 *tcp_seq_num, int payload_len)
+{
+    u8  tcp_fin  = tcp_flags & TCP_FIN;
+    u8  tcp_syn  = tcp_flags & TCP_SYN;
+    u8  tcp_rst  = tcp_flags & TCP_RST;
+    u8  tcp_push = tcp_flags & TCP_PUSH;
+    u8  tcp_ack  = tcp_flags & TCP_ACK;
+    u8  action   = TCP_DATA;
+
+    /*
+     * tcp_flags are examined to determine TX action in a given state
+     * tcp_push is intrepreted to mean "inform the app"
+     * urg, ece, cer and nonce flags are not supported.
+     *
+     * exe and crw are use to signal and confirm knowledge of congestion.
+     * This TCP only sends a file request and acks. If it generates
+     * congestion, the network is broken.
+     */
+
+    debug_cond(DEBUG_TCP_PKT, "TCP STATE ENTRY (%x)\n", action);
+    if (tcp_rst) {
+        action    = TCP_DATA;
+        tcp_state = TCP_CLOSED;
+        net_set_state(NETLOOP_FAIL);
+        debug_cond(DEBUG_TCP_PKT, "TCP Reset (%x)\n", tcp_flags);
+        return TCP_RST;
+    }
+
+    switch  (tcp_state) {
+    case TCP_CLOSED:
+    debug_cond(DEBUG_TCP_PKT, "TCP CLOSED (%x)\n", tcp_flags);
+        if (tcp_fin)
+            action = TCP_DATA;
+        if (tcp_syn)
+            action = TCP_RST;
+        if (tcp_ack)
+            action = TCP_DATA;
+    break;
+    case TCP_SYN_SENT:
+        debug_cond(DEBUG_TCP_PKT, "TCP_SYN_SENT (%x), %d\n",
+               tcp_flags, *tcp_seq_num);
+        if (tcp_fin) {
+            action = action | TCP_PUSH;
+            tcp_state = TCP_CLOSE_WAIT;
+        }
+        if (tcp_syn) {
+            action = action |  TCP_ACK;
+            if (tcp_ack) {
+                *tcp_seq_num = *tcp_seq_num + 1;
+                tcp_state    = TCP_ESTABLISHED;
+                action        = action | TCP_PUSH;
+                tcp_next_expected_seq_num = *tcp_seq_num;
+            }
+        } else {
+            if (tcp_ack)
+                action = TCP_DATA;
+        }
+    break;
+    case TCP_ESTABLISHED:
+        debug_cond(DEBUG_TCP_PKT,
+               "TCP_ESTABLISHED (%x)\n", tcp_flags);
+        if (tcp_fin) {
+            *tcp_seq_num = *tcp_seq_num + 1;
+            tcp_next_expected_seq_num++;
+            action    = action | TCP_FIN | TCP_PUSH | TCP_ACK;
+            tcp_state = TCP_CLOSE_WAIT;
+        } else {
+            if (tcp_ack)
+                action = TCP_DATA;
+        }
+        if (tcp_push)
+            action = action | TCP_PUSH;
+        if (tcp_syn)
+            action = TCP_ACK + TCP_RST;
+
+        if (*tcp_seq_num > tcp_next_expected_seq_num) {
+            tcp_hole_create(tcp_next_expected_seq_num,
+                    *tcp_seq_num);
+        debug_cond(DEBUG_TCP_PKT,
+               "TCP_ESTABLISHED Seq=%x, Exp=%x, A= %x\n",
+               *tcp_seq_num,
+               tcp_next_expected_seq_num, action);
+        }
+        if (*tcp_seq_num >= tcp_next_expected_seq_num)
+            tcp_next_expected_seq_num = *tcp_seq_num + payload_len;
+
+        debug_cond(DEBUG_TCP_PKT, "TCP_ESTABLISHED (%x), %d\n",
+               action, *tcp_seq_num);
+        break;
+    case TCP_CLOSE_WAIT:
+        debug_cond(DEBUG_TCP_PKT, "TCP_CLOSE_WAIT (%x)\n", tcp_flags);
+        action = TCP_DATA;            /* Wait for app    */
+    break;
+    case TCP_FIN_WAIT_2:
+        debug_cond(DEBUG_TCP_PKT, "TCP_FIN_WAIT_2 (%x)\n", tcp_flags);
+        if (tcp_fin)
+            action =  TCP_DATA;
+        if (tcp_syn)
+            action =  TCP_DATA;
+        if (tcp_ack) {
+            action =  TCP_PUSH | TCP_ACK;
+            tcp_state = TCP_CLOSED;
+        }
+    break;
+    case TCP_FIN_WAIT_1:
+        debug_cond(DEBUG_TCP_PKT, "TCP_FIN_WAIT_1 (%x)\n", tcp_flags);
+        if (tcp_fin) {
+            action = TCP_ACK | TCP_FIN;
+             tcp_state = TCP_FIN_WAIT_2;
+        }
+        if (tcp_syn)
+            action =  TCP_RST;
+        if (tcp_ack) {
+            tcp_state = TCP_CLOSED;
+             *tcp_seq_num = *tcp_seq_num + 1;
+        }
+    break;
+    case TCP_CLOSING:
+        debug_cond(DEBUG_TCP_PKT, "TCP_CLOSING (%x)\n", tcp_flags);
+        if (tcp_fin)
+            action = TCP_DATA;
+        if (tcp_syn)
+            action = TCP_RST;
+        if (tcp_ack) {
+            action = TCP_DATA;
+            tcp_state = TCP_CLOSED;
+        }
+    break;
+    }
+    return action;
+}
+
+void rxhand_tcp_f(union tcp_build_pkt *b, unsigned int pkt_len)
+{
+    int tcp_len     = pkt_len - IP_HDR_SIZE;
+    u16 tcp_rx_xsum = b->ip.hdr.ip_sum;
+    u8  tcp_action  = TCP_DATA;
+    u8  net_action  = TCP_DATA;
+    u32 tcp_seq_num;
+    u32 tcp_ack_num;
+    struct in_addr action_and_state;
+
+    int tcp_hdr_len;
+    int payload_len;
+
+    /*
+     * Verify ip header
+     */
+        debug_cond(DEBUG_TCP_PKT,
+               "TCP RX in RX Sum (to=%pI4, from=%pI4, len=%d)\n",
+               &b->ip.hdr.ip_src, &b->ip.hdr.ip_dst, pkt_len);
+
+        debug_cond(DEBUG_TCP_PKT,
+               "In__________________________________________\n");
+
+    b->ip.hdr.ip_src    = net_server_ip;
+    b->ip.hdr.ip_dst    = net_ip;
+    b->ip.hdr.ip_sum    = 0x0000;
+    if (tcp_rx_xsum != compute_ip_checksum(b, IP_HDR_SIZE)) {
+        debug_cond(DEBUG_TCP_PKT,
+               "TCP RX IP xum Error (%pI4, =%pI4, len=%d)\n",
+               &net_ip, &net_server_ip, pkt_len);
+        return;
+    }
+
+    /*
+     * Build Pseudo header and Verify TCP header
+     */
+    tcp_rx_xsum = b->ip.hdr.tcp_xsum;
+    b->ip.hdr.tcp_xsum = 0x0000;
+    if (tcp_rx_xsum != net_set_psuedo_header((uchar *)b, b->ip.hdr.ip_src,
+                         b->ip.hdr.ip_dst, tcp_len,
+                         pkt_len)) {
+        debug_cond(DEBUG_TCP_PKT,
+               "TCP RX TCP xSum Error (%pI4, %pI4, len=%d)\n",
+               &net_ip, &net_server_ip, tcp_len);
+        return;
+    }
+
+    tcp_hdr_len = (b->ip.hdr.tcp_hlen >> 2);
+    payload_len = tcp_len - tcp_hdr_len;
+
+    if (tcp_hdr_len > TCP_HDR_SIZE)
+        tcp_parse_options((uchar *)b + IP_TCP_HDR_SIZE,
+                  tcp_hdr_len - TCP_HDR_SIZE);
+    /*
+     * Incoming sequence and ack numbers are server's view of the numbers.
+     * The app must swap the numbers when responding.
+     */
+
+    tcp_seq_num = ntohl(b->ip.hdr.tcp_seq);
+    tcp_ack_num = ntohl(b->ip.hdr.tcp_ack);
+
+    tcp_action  = tcp_state_machine(b->ip.hdr.tcp_flags,
+                    &tcp_seq_num, payload_len);
+
+    /*
+     * State altering command to be sent.
+     * The packet sequence and ack numbers are in the tcp_seq_num
+     * and tcp_ack_num variables. The current packet, its position
+     * in the date stream, is the in the range of those variables.
+     *
+     * In the "application push" invocation the TCP header with all
+     * its information is pointed to by the packet pointer, and the
+     * other variable "repurposed" (or misused) to carry sequence numbers
+     * and  TCP state.
+     *
+     * TCP_PUSH from the state machine with a payload length of 0 is a
+     * connect or disconnect event
+     */
+
+    if ((tcp_action && TCP_PUSH) || (payload_len > 0)) {
+        debug_cond(DEBUG_TCP_PKT,
+               "TCP Notify (action=%x, Seq=%d,Ack=%d,Pay%d)\n",
+               tcp_action, tcp_seq_num, tcp_ack_num, payload_len);
+
+        action_and_state.s_addr = tcp_action;
+        (*tcp_packet_handler) ((uchar *)b + pkt_len - payload_len,
+                       tcp_seq_num, action_and_state,
+                       tcp_ack_num, payload_len);
+
+    } else if (tcp_action != TCP_DATA) {
+        debug_cond(DEBUG_TCP_PKT,
+               "TCP Action (action=%x,Seq=%d,Ack=%d,Pay=%d)\n",
+               tcp_action, tcp_seq_num, tcp_ack_num, payload_len);
+
+    /*
+     * Warning: Incoming Seq & Ack  sequence numbers are transposed here
+     * to outgoing Seq & Ack sequence numbers
+     */
+
+        net_action = (tcp_action & (~TCP_PUSH));
+        net_send_ip_packet(0, IPPROTO_TCP, net_action,
+                   tcp_ack_num, tcp_seq_num);
+    }
+}
+#endif
diff --git a/net/ping.c b/net/ping.c
index 9508cf1160..254b646193 100644
--- a/net/ping.c
+++ b/net/ping.c
@@ -20,16 +20,11 @@ struct in_addr net_ping_ip;
 static void set_icmp_header(uchar *pkt, struct in_addr dest)
 {
     /*
-     *    Construct an IP and ICMP header.
+     *    Construct an ICMP header.
      */
-    struct ip_hdr *ip = (struct ip_hdr *)pkt;
     struct icmp_hdr *icmp = (struct icmp_hdr *)(pkt + IP_HDR_SIZE);
 
-    net_set_ip_header(pkt, dest, net_ip);
-
-    ip->ip_len   = htons(IP_ICMP_HDR_SIZE);
-    ip->ip_p     = IPPROTO_ICMP;
-    ip->ip_sum   = compute_ip_checksum(ip, IP_HDR_SIZE);
+    net_set_ip_header(pkt, dest, net_ip, IP_ICMP_HDR_SIZE, IPPROTO_ICMP);
 
     icmp->type = ICMP_ECHO_REQUEST;
     icmp->code = 0;
diff --git a/net/wget.c b/net/wget.c
new file mode 100644
index 0000000000..cc5ef4f0c2
--- /dev/null
+++ b/net/wget.c
@@ -0,0 +1,354 @@
+/*
+ * FILE  support driver - based on etherboot and U-BOOT's tftp.c
+ *
+ * Copyright Duncan Hare <dh at synoia.com> 2017
+ *
+ * SPDX-License-Identifier:<TAB>GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <fat.h>    //FAT
+#include <net.h>
+#include <mapmem.h>
+#define        FILE_TEST 0    /* Set to 1 for debug messges */
+#define        SERVER_PORT    8081
+#define        FILE_RETRY_COUNT 30
+#define        FILE_TIMEOUT    2000UL
+
+char bootfile1[10]    = "GET ";
+char bootfile3[20]    = " HTTP/1.1\r\n\r\n";
+uchar content[6]    = "<html>";
+uchar error404[3]    = "404";
+static struct    in_addr file_server_ip;
+static int    file_timeout_count;
+int packets;
+static u32 initial_data_seq_num;
+
+enum FILE_STATE {
+    FILE_CLOSED,
+    FILE_CONNECTING,
+    FILE_CONNECTED,
+    FILE_TRANSFERRING,
+    FILE_TRANSFERRED};
+
+static enum  FILE_STATE file_state;
+
+static char *file_filename;
+static char *file_path;
+static char file_path_buff[2048];
+static unsigned int file_timeout = FILE_TIMEOUT;
+static void file_timeout_handler(void);
+void file_fail(char *error_message, unsigned int tcp_seq_num,
+           unsigned int tcp_ack_num, u8 action);
+
+static inline int store_block(uchar *src, unsigned int offset, unsigned int len)
+{
+    ulong newsize = offset + len;
+
+#ifdef CONFIG_SYS_DIRECT_FLASH_WGET
+    int i, rc = 0;
+
+    for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
+        /* start address in flash? */
+        if (load_addr + offset >= flash_info[i].start[0]) {
+            rc = 1;
+            break;
+        }
+    }
+
+    if (rc) { /* Flash is destination for this packet */
+        rc = flash_write((uchar *)src,
+                 (ulong)(load_addr + offset), len);
+        if (rc) {
+            flash_perror(rc);
+            return -1;
+        }
+    } else {
+#endif /* CONFIG_SYS_DIRECT_FLASH_NFS */
+
+        uchar *ptr = map_sysmem(load_addr + offset, len);
+
+        memcpy(ptr, src, len);
+        unmap_sysmem(ptr);
+
+#ifdef CONFIG_SYS_DIRECT_FLASH_WGET
+    }
+#endif
+    if (net_boot_file_size < (offset + len))
+        net_boot_file_size = newsize;
+    return 0;
+}
+
+/*
+ * File request dispatcher
+ * WARNING, This, and only this, is the place where
+ * SEQUENCE NUMBERS are swapped betweeen incoming (RX)  and outgoing (TX)
+ * What is in procedure file_handler() is correct for RX traffic.
+ */
+static void file_send(u8 action, unsigned int tcp_ack_num,
+              unsigned int tcp_seq_num, int len)
+{
+    uchar *ptr;
+    uchar *offset;
+
+    tcp_ack_num = tcp_ack_num + len;
+
+    switch (file_state) {
+    case FILE_CLOSED:
+        debug_cond(FILE_TEST, "File send: send SYN\n");
+        file_state = FILE_CONNECTING;
+        net_send_ip_packet(0, IPPROTO_TCP, action,
+                   tcp_seq_num, tcp_ack_num);
+        packets = 0;
+    break;
+    case FILE_CONNECTING:
+        debug_cond(FILE_TEST, "File send: send HTTP GET\n");
+
+        ptr = net_tx_packet + net_eth_hdr_size()
+            + IP_TCP_HDR_SIZE + TCP_TSOPT_SIZE + 2;
+        offset = ptr;
+
+        memcpy(offset, &bootfile1, strlen(bootfile1));
+        offset = offset + strlen(bootfile1);
+
+        memcpy(offset, file_path, strlen(file_path));
+        offset = offset + strlen(file_path);
+
+        memcpy(offset, &bootfile3, strlen(bootfile3));
+        offset = offset + strlen(bootfile3);
+        net_send_ip_packet((offset - ptr), IPPROTO_TCP,
+                   TCP_DATA, tcp_seq_num, tcp_ack_num);
+        file_state = FILE_CONNECTED;
+    break;
+    case FILE_CONNECTED:
+        debug_cond(FILE_TEST, "File send: Header\n");
+        file_state = FILE_TRANSFERRING;
+    break;
+    case FILE_TRANSFERRING:
+        debug_cond(FILE_TEST, "File send:Transferring\n");
+        net_send_ip_packet(0, IPPROTO_TCP, action,
+                   tcp_seq_num, tcp_ack_num);
+    break;
+    case FILE_TRANSFERRED:
+
+        debug_cond(FILE_TEST, "File send:Transferred\n");
+        net_send_ip_packet(0, IPPROTO_TCP, action,
+                   tcp_seq_num, tcp_ack_num);
+    break;
+    }
+}
+
+void file_success(u8 action, unsigned int tcp_seq_num,
+          unsigned int tcp_ack_num, int len, int packets)
+{
+    file_state = FILE_TRANSFERRED;
+    net_set_state(NETLOOP_SUCCESS);
+    net_set_timeout_handler(0, NULL);
+    debug_cond(1, "Packets received %d, File send:SUCCESS!!!\n", packets);
+    file_send(action, tcp_seq_num, tcp_ack_num, len);
+}
+
+void file_fail(char *error_message, unsigned int tcp_seq_num,
+           unsigned int tcp_ack_num, u8 action)
+{
+    printf("%s", error_message);
+    printf("%s", "File Fail\n");
+    file_state = FILE_TRANSFERRED;
+    net_set_timeout_handler(0, NULL);
+    net_set_state(NETLOOP_FAIL);
+    file_send(action | TCP_FIN, tcp_seq_num, tcp_ack_num, 0);
+}
+
+/*
+ * Interfaces of U-BOOT
+ */
+static void file_timeout_handler(void)
+{
+    if (++file_timeout_count > FILE_RETRY_COUNT) {
+        puts("\nRetry count exceeded; starting again\n");
+        net_start_again();
+    } else {
+        puts("T ");
+        net_set_timeout_handler(file_timeout +
+                    FILE_TIMEOUT * file_timeout_count,
+                    file_timeout_handler);
+        file_send(TCP_DATA, 0, 0, 0);
+    }
+}
+
+    /*
+     * In the "application push" invocation the TCP header with all its
+     * information is the packet pointer, and the other variable
+     * "repurposed" (or misused) to carry sequence numbers and  TCP state.
+     *
+     */
+
+static void file_handler(uchar *pkt, unsigned int tcp_seq_num,
+             struct in_addr action_and_state,
+             unsigned int tcp_ack_num, unsigned int len)
+{
+    enum TCP_STATE file_tcp_state = net_get_tcp_state();
+    u8 action = action_and_state.s_addr;
+    int offset;
+
+    net_set_timeout_handler(file_timeout, file_timeout_handler);
+    packets++;
+
+    switch (file_state) {
+    case FILE_CLOSED:
+        debug_cond(FILE_TEST, "File Handler: Error!, State wrong\n");
+    break;
+    case FILE_CONNECTING:
+        debug_cond(FILE_TEST,
+               "File Connecting In len=%d, Seq=%d, Ack=%d\n",
+               len, tcp_seq_num, tcp_ack_num);
+        if (len == 0) {
+            if (file_tcp_state == TCP_ESTABLISHED) {
+                debug_cond(FILE_TEST,
+                       "File Cting, send, len=%d\n", len);
+            file_send(action, tcp_seq_num, tcp_ack_num, len);
+            } else {
+                file_fail("File Handler Connected Fail\n",
+                      tcp_seq_num, tcp_ack_num, action);
+            }
+        }
+    break;
+    case FILE_CONNECTED:
+        debug_cond(FILE_TEST, "File Cted In len=%d, seq=%d, ack=%d\n",
+               len, tcp_seq_num, tcp_ack_num);
+        if (len == 0) {
+            file_fail("File not found, no data returned/n",
+                  tcp_seq_num, tcp_ack_num, action);
+        } else {
+            if (net_find_in_buffer(pkt, len, error404, 3)  > 0) {
+                offset = net_find_in_buffer(pkt, len,
+                                content, 6);
+                net_print_buffer(pkt, offset - 4,
+                         offset - 4, -1, 0);
+                file_fail((char *)pkt, tcp_seq_num,
+                      tcp_ack_num, action);
+            } else {
+                net_print_buffer(pkt, len, len, -1, 0);
+                file_state = FILE_TRANSFERRING;
+                initial_data_seq_num = tcp_seq_num + len;
+                file_send(action, tcp_seq_num,
+                      tcp_ack_num, len);
+            }
+        }
+    break;
+    case FILE_TRANSFERRING:
+        debug_cond(FILE_TEST,
+               "File Transferring, seq=%d, ack=%d,len=%d\n",
+               tcp_seq_num, tcp_ack_num, len);
+
+        if (len ==  0) {
+            file_send(action, tcp_seq_num, tcp_ack_num, len);
+        } else {
+            offset = tcp_seq_num - initial_data_seq_num;
+            if (store_block(pkt, offset, len) != 0) {
+                file_fail("File store error\n",
+                      tcp_seq_num,
+                      tcp_ack_num,
+                      action);
+            } else {
+                switch (file_tcp_state) {
+                case TCP_SYN_SENT:
+                case TCP_CLOSING:
+                case TCP_FIN_WAIT_1:
+                case TCP_FIN_WAIT_2:
+                case TCP_CLOSED:
+                    net_set_state(NETLOOP_FAIL);
+                break;
+                case TCP_ESTABLISHED:
+                    file_send(TCP_ACK, tcp_seq_num,
+                          tcp_ack_num, len);
+                break;
+                case TCP_CLOSE_WAIT:     /* End of file */
+                    file_success(action | TCP_ACK,
+                             tcp_seq_num, tcp_ack_num,
+                             len, packets);
+                break;
+                }
+            }
+        }
+    break;
+    case FILE_TRANSFERRED:
+        file_send(TCP_ACK, tcp_seq_num, tcp_ack_num, len);
+    break;
+    }
+}
+
+void wget_start(void)
+{
+    debug("%s\n", __func__);
+
+    file_server_ip = net_server_ip;
+    file_path = (char *)file_path_buff;
+
+    if (!file_path) {
+        net_set_state(NETLOOP_FAIL);
+        debug("*** ERROR: Fail allocate memory\n");
+        return;
+    }
+
+    if (net_boot_file_name[0] == '\0') {
+        sprintf(file_path, "/fileroot/%02X%02X%02X%02X.img",
+            net_ip.s_addr & 0xFF,
+            (net_ip.s_addr >>  8) & 0xFF,
+            (net_ip.s_addr >> 16) & 0xFF,
+            (net_ip.s_addr >> 24) & 0xFF);
+
+        debug("*** Warning: no boot file name; using '%s'\n",
+              file_path);
+    } else {
+        char *p = net_boot_file_name;
+
+        p = strchr(p, ':');
+
+        if (!p) {
+            file_server_ip = string_to_ip(net_boot_file_name);
+            ++p;
+            strcpy(file_path, p);
+        } else {
+            strcpy(file_path, net_boot_file_name);
+        }
+    }
+
+    debug_cond(FILE_TEST, "Using %s device\n", eth_get_name());
+    debug_cond(FILE_TEST, "File transfer HTTP Server %pI4; our IP %pI4\n",
+           &file_server_ip, &net_ip);
+
+    /* Check if we need to send across this subnet */
+    if (net_gateway.s_addr && net_netmask.s_addr) {
+        struct in_addr our_net;
+        struct in_addr server_net;
+
+        our_net.s_addr = net_ip.s_addr & net_netmask.s_addr;
+        server_net.s_addr = net_server_ip.s_addr & net_netmask.s_addr;
+        if (our_net.s_addr != server_net.s_addr)
+            debug("; sending through gateway %pI4",
+                  &net_gateway);
+    }
+    debug_cond(FILE_TEST, "Filename '%s, %s'.\n", file_path, file_filename);
+
+    if (net_boot_file_expected_size_in_blocks) {
+        debug(" Size is 0x%x Bytes = ",
+              net_boot_file_expected_size_in_blocks << 9);
+        print_size(net_boot_file_expected_size_in_blocks << 9, "");
+    }
+    debug("\nLoad address: 0x%lx\nLoading: *\b", load_addr);
+
+    net_set_timeout_handler(file_timeout, file_timeout_handler);
+    net_set_tcp_handler(file_handler);
+
+    file_timeout_count = 0;
+    file_state = FILE_CLOSED;
+
+    net_set_ports(SERVER_PORT, 4096 + (get_ticks() % 3072));
+
+    /* zero out server ether in case the server ip has changed */
+    memset(net_server_ethaddr, 0, 6);
+
+    file_send(TCP_SYN, 0, 0, 0);
+}
diff --git a/net/wget.h b/net/wget.h
new file mode 100644
index 0000000000..80e6400247
--- /dev/null
+++ b/net/wget.h
@@ -0,0 +1,6 @@
+/*
+ * Duncan Hare Copyright 2017
+*/
+
+void wget_start(void);   /* Begin wget */
+
-- 
2.11.0



More information about the U-Boot mailing list