Mods to:
cmd/net.cnet/Makefilenet/net.cinclude/net.hnet/wget.cnet/wget.hnet/ping.c
I do not know how to do patches, I'm a noobat this:
cmd/net.c
Additions
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]");
net/Makefile addition
obj-$(CONFIG_CMD_NFS)  += wget.o

net.c  complete, look for #ifdef TCP
 /*
 *      Copied from Linux Monitor (LiMon) - Networking.
 *
 *      Copyright 1994 - 2000 Neil Russell.
 *      (See License)
 *      Copyright 2000 Roland Borde
 *      Copyright 2000 Paolo Scaffardi
 *      Copyright 2000-2002 Wolfgang Denk, w...@denx.de
 *      Copyright 2017-2018 Duncan Hare, d...@synoia.com
 *      SPDX-License-Identifier:        GPL-2.0
 */
#define TCP 1
/*
 * General Desription:
 *
 * The user interface supports commands for BOOTP, RARP, and TFTP.
 * Also, we support ARP internally. Depending on available data,
 * these interact as follows:
 *
 * BOOTP:
 *
 *      Prerequisites:  - own ethernet address
 *      We want:        - own IP address
 *                      - TFTP server IP address
 *                      - name of bootfile
 *      Next step:      ARP
 *
 * LINK_LOCAL:
 *
 *      Prerequisites:  - own ethernet address
 *      We want:        - own IP address
 *      Next step:      ARP
 *
 * RARP:
 *
 *      Prerequisites:  - own ethernet address
 *      We want:        - own IP address
 *                      - TFTP server IP address
 *      Next step:      ARP
 *
 * ARP:
 *
 *      Prerequisites:  - own ethernet address
 *                      - own IP address
 *                      - TFTP server IP address
 *      We want:        - TFTP server ethernet address
 *      Next step:      TFTP
 *
 * DHCP:
 *
 *     Prerequisites:   - own ethernet address
 *     We want:         - IP, Netmask, ServerIP, Gateway IP
 *                      - bootfilename, lease time
 *     Next step:       - TFTP
 *
 * TFTP:
 *
 *      Prerequisites:  - own ethernet address
 *                      - own IP address
 *                      - TFTP server IP address
 *                      - TFTP server ethernet address
 *                      - name of bootfile (if unknown, we use a default name
 *                        derived from our own IP address)
 *      We want:        - load the boot file
 *      Next step:      none
 *
 * NFS:
 *
 *      Prerequisites:  - own ethernet address
 *                      - own IP address
 *                      - name of bootfile (if unknown, we use a default name
 *                        derived from our own IP address)
 *      We want:        - load the boot file
 *      Next step:      none
 *
 * SNTP:
 *
 *      Prerequisites:  - own ethernet address
 *                      - 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_DCH_PKT 1
#define DEBUG_TCP_PKT 0

#include <common.h>
#include <command.h>
#include <console.h>
#include <environment.h>
#include <errno.h>
#include <net.h>
#include <net/tftp.h>
#if defined(CONFIG_STATUS_LED)
#include <miiphy.h>
#include <status_led.h>
#endif
#include <watchdog.h>
#include <linux/compiler.h>
#include "arp.h"
#include "bootp.h"
#include "cdp.h"
#if defined(CONFIG_CMD_DNS)
#include "dns.h"
#endif
#include "link_local.h"
#include "nfs.h"
#include "wget.h"
#include "ping.h"
#include "rarp.h"
#if defined(CONFIG_CMD_SNTP)
#include "sntp.h"
#endif

DECLARE_GLOBAL_DATA_PTR;

/** BOOTP EXTENTIONS **/

/* Our subnet mask (0=unknown) */
struct in_addr net_netmask;
/* Our gateways IP address */
struct in_addr net_gateway;
/* Our DNS IP address */
struct in_addr net_dns_server;
#if defined(CONFIG_BOOTP_DNS2)
/* Our 2nd DNS IP address */
struct in_addr net_dns_server2;
#endif

#ifdef CONFIG_MCAST_TFTP        /* Multicast TFTP */
struct in_addr net_mcast_addr;
#endif

/** END OF BOOTP EXTENTIONS **/

/* Our ethernet address */
u8 net_ethaddr[6];
/* Boot server enet address */
u8 net_server_ethaddr[6];
/* Our IP addr (0 = unknown) */
struct in_addr  net_ip;
/* Server IP addr (0 = unknown) */
struct in_addr  net_server_ip;
/* Port numbers                 */
int dport;
int sport;
/* Current receive packet */
uchar *net_rx_packet;
/* Current rx max packet length */
int net_rx_packet_len;
/* IP packet ID */
static unsigned net_ip_id; 
/* Ethernet bcast address */
const u8 net_bcast_ethaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
const u8 net_null_ethaddr[6];
#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
void (*push_packet)(void *, int len) = 0;
#endif
/* Network loop state */
enum net_loop_state net_state;
/* Tried all network devices */
int             net_restart_wrap;
/* Network loop restarted */
static int      net_restarted;
/* At least one device configured */
static int      net_dev_exists;

#ifdef TCP

/* TCP sliding window  control  */
static u32 tcp_next_expected_seq_num;
static struct tcp_sack_v tcp_lost;                      /* used by us to 
request re-TX          */

struct w_manage {
        struct sack_edges tcp_hole;
        enum acked { FALSE, TRUE, FILLED } sent;
        int age;
};

static int tcp_max_hole;

struct w_manage holes[TCP_STREAM_HOLES];

/* TCP option timestamp */

static u32 loc_timestamp;
static u32 rmt_timestamp;

/* TCP connection state */
static enum TCP_STATE tcp_state;

#endif

/* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
/* default is without VLAN */
ushort          net_our_vlan = 0xFFFF;
/* ditto */
ushort          net_native_vlan = 0xFFFF;

/* Boot File name */
char net_boot_file_name[1024];
/* The actual transferred size of the bootfile (in bytes) */
u32 net_boot_file_size;
/* Boot file size in blocks as reported by the DHCP server */
u32 net_boot_file_expected_size_in_blocks;

#if defined(CONFIG_CMD_SNTP)
/* NTP server IP address */
struct in_addr  net_ntp_server;
/* offset time from UTC */
int             net_ntp_time_offset;
#endif

static uchar net_pkt_buf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
/* Receive packets */
uchar *net_rx_packets[PKTBUFSRX];

/*
 * 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 len);

/* 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 */
static rxhand_f *arp_packet_handler;
#ifdef CONFIG_CMD_TFTPPUT
/* Current ICMP rx handler */
static rxhand_icmp_f *packet_icmp_handler;
#endif
/* Current timeout handler */
static thand_f *time_handler;
/* Time base value */
static ulong    time_start;
/* Current timeout value */
static ulong    time_delta;
/* THE transmit packet */
uchar *net_tx_packet;

static int net_check_prereq(enum proto_t protocol);

static int net_try_count;

int __maybe_unused net_busy_flag;

/**********************************************************************/

static int on_bootfile(const char *name, const char *value, enum env_op op,
        int flags)
{
        if (flags & H_PROGRAMMATIC)
                return 0;

        switch (op) {
        case env_op_create:
        case env_op_overwrite:
                copy_filename(net_boot_file_name, value,
                              sizeof(net_boot_file_name));
                break;
        default:
                break;
        }

        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)
{
        if (flags & H_PROGRAMMATIC)
                return 0;

        net_ip = string_to_ip(value);

        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)
{
        if (flags & H_PROGRAMMATIC)
                return 0;

        net_gateway = string_to_ip(value);

        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)
{
        if (flags & H_PROGRAMMATIC)
                return 0;

        net_netmask = string_to_ip(value);

        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)
{
        if (flags & H_PROGRAMMATIC)
                return 0;

        net_server_ip = string_to_ip(value);

        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)
{
        if (flags & H_PROGRAMMATIC)
                return 0;

        net_native_vlan = string_to_vlan(value);

        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)
{
        if (flags & H_PROGRAMMATIC)
                return 0;

        net_our_vlan = string_to_vlan(value);

        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)
{
        if (flags & H_PROGRAMMATIC)
                return 0;

        net_dns_server = string_to_ip(value);

        return 0;
}
U_BOOT_ENV_CALLBACK(dnsip, on_dnsip);
#endif

/*
 * Check if autoload is enabled. If so, use either NFS or TFTP to download
 * the boot file.
 */
void net_auto_load(void)
{
#if defined(CONFIG_CMD_NFS)
        const char *s = getenv("autoload");

        if (s != NULL && strcmp(s, "NFS") == 0) {
                /*
                 * Use NFS to load the bootfile.
                 */
                nfs_start();
                return;
        }
#endif
        if (getenv_yesno("autoload") == 0) {
                /*
                 * Just use BOOTP/RARP to configure system;
                 * Do not use TFTP to load the bootfile.
                 */
                net_set_state(NETLOOP_SUCCESS);
                return;
        }
        tftp_start(TFTPGET);
}

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);
}

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;
}


#ifdef 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]);

//              else printf ("%s",".");
        }
        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
        */
        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, 
CheckLen=%d)\n",
                        &b->ph.p_dst, &b->ph.p_src, checksum_len );
        /*
         *      If the data is an odd number of bytes, zero the
         *      byte after the last byte so that the header checksum
         *      will work.
         */

        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[1].l        = htonl(tcp_lost.hole[1].l);
                b->sack.sack_v.hole[1].r        = htonl(tcp_lost.hole[1].r);

                /*
                * These fields are initialized with NOPs to
                * provide TCP header alignment padding
                */

                b->sack.sack_v.hole[2].l        = htonl(tcp_lost.hole[1].l);
                b->sack.sack_v.hole[2].r        = htonl(tcp_lost.hole[1].r);
                b->sack.sack_v.hole[3].l        = htonl(tcp_lost.hole[2].l);
                b->sack.sack_v.hole[3].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;                 /* hdr 10 32 bit words  
*/

        b->ip.mss.kind          = TCP_O_MSS;
        b->ip.mss.len           = TCP_OPT_LEN_4;
        b->ip.mss.mss           = htons(TCP_MSS);       /* tunable parameter    
*/
        b->ip.scale.kind        = TCP_O_SCL;
        b->ip.scale.scale       = TCP_SCALE;            /* tunable parameter    
*/
        b->ip.scale.len         = TCP_OPT_LEN_3;
        b->ip.sack_p.kind       = TCP_P_SACK ;          /* SACK supported       
*/
        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              */
        switch (action)                                         /* For options  
                */
        {
                case TCP_SYN:
                        debug_cond(DEBUG_TCP_PKT,
                                "TCP Header:SYN  (to=%pI4, from=%pI4, 
TCPseq=%d, TCPack=%d)\n",
                                        &net_server_ip, &net_ip, tcp_seq_num, 
tcp_ack_num);

                        net_set_syn_options( b );
                        tcp_seq_num             = 0;                    /* TCP 
sequence number  */
                        tcp_ack_num             = 0;                    /* TCP 
Ack Number       */
                        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 Header:ACK (to=%pI4, from=%pI4, TCPseq=%d, 
TCPack=%d, Action=%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 Header:FIN  (to=%pI4, from=%pI4, 
TCPseq=%d, TCPack=%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):
                case (TCP_FIN + TCP_ACK + TCP_PUSH):
                        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 Header:default  (to=%pI4, from=%pI4, 
TCPseq=%d, TCPack=%d, Action=%x)\n",
                                &net_server_ip, &net_ip, tcp_seq_num, 
tcp_ack_num, b->ip.hdr.tcp_flags);
        }
        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.
         * Chage 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 not 
considered a constraint to
         * buffer space.
        */

        b->ip.hdr.tcp_win       = htons( PKTBUFSRX * TCP_MSS >> TCP_SCALE );

        b->ip.hdr.tcp_xsum      = 0x0000;                       /* Checksum     
                */
        b->ip.hdr.tcp_ugr       = 0x0000;                       /* Pointer to 
urgent data       */

        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 );
}

#endif

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;


        if ( proto == IPPROTO_UDP )
        { debug_cond(DEBUG_DEV_PKT,
                           "UDP Send  (to=%pI4, from=%pI4, len=%d)\n",
                           &net_server_ip, &net_ip, payload_len);
        }
#ifdef TCP
        else
        { debug_cond(DEBUG_TCP_PKT,
                           "TCP Send  (to=%pI4, from=%pI4, len=%d, 
Action=%x)\n",
                           &net_server_ip, &net_ip, payload_len, action );
        }
#endif

        /* make sure the net_tx_packet is initialized (net_init() was called) */
        assert(net_tx_packet != NULL);
        if (net_tx_packet == NULL) return -1;

        /* convert to new style broadcast */
        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 (net_server_ip.s_addr == 0xFFFFFFFF) ether = (uchar 
*)net_bcast_ethaddr;

        pkt = (uchar *)net_tx_packet;

        /*
         *Get ethernet header size and write the ethernet header
        */

        eth_hdr_size  = net_set_ether(pkt, ether, PROT_IP);

#ifdef 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;
#ifdef 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", 
&net_server_ip);

                /* save the ip and eth addr for the packet to send after arp */
                net_arp_wait_packet_ip = net_server_ip;
                arp_wait_packet_ethaddr = ether;

                /* size of the waiting packet */
                arp_wait_tx_packet_size = pkt_hdr_size + payload_len;

                /* and do the ARP request */
                arp_wait_try = 1;
                arp_wait_timer_start = get_timer(0);
                arp_request();
                return 1;       /* waiting */
        } else {
                debug_cond(DEBUG_DEV_PKT, "sending TCP to %pI4/%pM/%d\n",
                           &net_server_ip, ether, pkt_hdr_size + payload_len);
                net_send_packet(net_tx_packet, pkt_hdr_size + payload_len);
                return 0;       /* transmitted */
        }
}

#ifdef TCP

int tcp_hole_age ( int age )
{
        int i, j = 0, filled = 0;

        tcp_lost.len            = TCP_OPT_LEN_2;
        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;

        tcp_lost.kind           = TCP_V_SACK;

        for (i = 0; (( i == tcp_max_hole ) || ( j == 2 )) ; i++ )
        {
                if (( holes[i].tcp_hole.l != 0 ) && ( holes[i].sent == FALSE ))
                {
                        if ( holes[i].age <= TCP_HOLE_AGE ) holes[i].age++;
                        else
                        {
                                /*
                                * Ask for hole to be filled by sender on next 
ack response.
                                */
                                tcp_lost.len            = tcp_lost.len + 
TCP_OPT_LEN_8;
                                tcp_lost.hole[j].l      = holes[i].tcp_hole.l;
                                tcp_lost.hole[j].l      = holes[i].tcp_hole.r;
                                holes[i].sent           = TRUE;
                                j++;
                        }
                }
                if (( holes[i].tcp_hole.l == 0 ) || ( holes[i].sent == FILLED 
)) filled++;

                switch (holes[i].sent)
                {
                        case FALSE:
                                debug_cond( DEBUG_DCH_PKT, ".");
                        break;
                        case TRUE:
                                debug_cond( DEBUG_DCH_PKT, "o");
                        break;
                        case FILLED:
                                debug_cond( DEBUG_DCH_PKT, "|");
                        break;
                }
        }
        debug_cond( DEBUG_DCH_PKT, "\n");

        /*
         * No holes found? Set return code.
        */

        if ( tcp_lost.len == TCP_OPT_LEN_2 )
        {
                tcp_lost.len = 0;
                return ( filled - tcp_max_hole );
        }
        else return ( 1 );
}

void tcp_hole_fill( u32 tcp_left, u32 tcp_right )
{
        int i ,j;

        for ( i = 0; (( i = tcp_max_hole ) || ( tcp_left != holes[i].tcp_hole.l 
)); i++ );

        if ( tcp_left == holes[i].tcp_hole.l )
        {
                holes[i].sent = FILLED;
                /*
                 * Move holes to down hole array as preceeding holes become 
filled
                */
                for ( j = i; (j < tcp_max_hole); j++ )
                {
                        holes[j] = holes[j + 1];
                }
        }
        else debug_cond( DEBUG_DCH_PKT, "Error: Hole not found: Left=%d\n", 
tcp_left );
}

void tcp_hole_create( u32 tcp_left, u32 tcp_right )
{
        debug_cond( 1, "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_hole_create_complex( u32 tcp_left, u32 tcp_right )
{
        int i;

        for (i = 0; i < TCP_STREAM_HOLES; i++ )
        {
                /*
                 * Find empty hole struct and fill it
                */
                if ( holes[i].tcp_hole.l == 0 )
                holes[i].tcp_hole.l     = tcp_left;
                holes[i].tcp_hole.r     = tcp_right;
                holes[i].sent           = FALSE;
                holes[i].age            = 0;
                if ( i > tcp_max_hole ) tcp_max_hole = i;
                return;
        }
        debug_cond( 1, "Error: Too many TCP erorrs, increase TCP_STREAM_HOLES 
or get a better network\n");
        net_set_state(NETLOOP_FAIL);

}


void init_tcp_holes( u32 tcp_seq_num )
{
        int i;

        for (i = 0; i < TCP_STREAM_HOLES; i++)
        {
                holes[i].tcp_hole.l     = 0;
                holes[i].tcp_hole.r     = 0;
                holes[i].sent           = FALSE;
                holes[i].age            = 0;
        }

        tcp_next_expected_seq_num       = tcp_seq_num;
        /*
         * // For production set to 0.
         * // For testingt set to TCP_STREAM_HOLES - 1
        */
        tcp_max_hole                    = TCP_STREAM_HOLES - 1;         // For 
testing.
                                                                        // For 
production set 0.
}

void tcp_parse_options( uchar *o, int o_len)
{
        struct tcp_TSopt  *tsopt;
        uchar *p = o;

        for ( p = o; p < (o + o_len); p = p + p[1])
        {
                if (p[1] == 0) return;
                else
                {
                        switch ( p[0] )
                        {
                                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;
                        }
                        if (p[0] == TCP_O_NOP) p++;
                }
        }
        return;
}

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  tcp_urg     = tcp_flags & TCP_URG;
        u8  tcp_ece     = tcp_flags & TCP_ECE;
        u8  tcp_cwr     = tcp_flags & TCP_CWR;
        u8  action      = TCP_DATA;

        /*
         * tcp_flags are examined to determine TX action in a given state
         * tcp_options, if not zero, is a pointer to the TCP options,
         * to extract the receive timestamp value
        */

        /*
         * These flags are not supported.
        */
        if (tcp_urg)    action = action;
        if (tcp_ece)    action = action;
        if (tcp_cwr)    action = action;

        debug_cond(DEBUG_INT_STATE, "TCP STATE ENTRY (%x)\n", action);
        if (tcp_rst)
        {
                action          = TCP_DATA;
                tcp_state       = TCP_CLOSED;
                net_set_state( NETLOOP_FAIL );
                debug_cond(DEBUG_DCH_PKT, "TCP Reset (%x)\n", tcp_flags);
        }
        else switch  (tcp_state)
        {
                case    TCP_CLOSED:                                     /* 
Should never happen  */
                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;      
/* SACK         */
                                        action          = action | TCP_PUSH;    
/* Notify app   */
                                        init_tcp_holes( *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)
                        {       /*
                                 * Check for holes !!
                                */
                                *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;

/*                      tcp_hole_age( TCP_HOLE_AGE );

                        if (*tcp_seq_num < tcp_next_expected_seq_num )
                        tcp_hole_fill( *tcp_seq_num, payload_len );
                        else
                        {
*/                              if (*tcp_seq_num > tcp_next_expected_seq_num )
                                {
                                        tcp_hole_create( 
tcp_next_expected_seq_num, *tcp_seq_num );
                                        debug_cond(DEBUG_DCH_PKT,
                                                "TCP_ESTABLISHED Seq In %x, Exp 
%x, action %x\n",
                                                *tcp_seq_num, 
tcp_next_expected_seq_num, action);
                                }
                                if (*tcp_seq_num != tcp_next_expected_seq_num )
                                net_set_state( NETLOOP_FAIL );
                                else 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_DCH_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;}
                        net_set_state( NETLOOP_FAIL );
                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 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,
                        "____________________________________________\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 (to=%pI4, from=%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 (to=%pI4, from=%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 App Notify (action=%x, Seq=%d, Ack=%d, 
Payload=%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 Net Action (action=%x, Seq=%d, 
Ack=%d,Payload=%d)\n",
                                tcp_action, tcp_seq_num, tcp_ack_num, 
payload_len );

        /*
         * Warning Incoming sequence number are transposed here to TX sequence 
numbers
        */

                net_action = (tcp_action & (~ TCP_PUSH));
                net_send_ip_packet( 0, IPPROTO_TCP, net_action, tcp_ack_num, 
tcp_seq_num );
        }
}

#endif

void net_init(void)
{
        static int first_call = 1;

        if (first_call) {
                /*
                 *      Setup packet wbuffers, aligned correctly.
                 */
                int i;

                net_tx_packet = &net_pkt_buf[0] + (PKTALIGN - 1);
                net_tx_packet -= (ulong)net_tx_packet % PKTALIGN;
                for (i = 0; i < PKTBUFSRX; i++) {
                        net_rx_packets[i] = net_tx_packet +
                                (i + 1) * PKTSIZE_ALIGN;
                }
                arp_init();
                net_clear_handlers();

                /* Only need to setup buffer pointers once. */
                first_call = 0;
#ifdef TCP
                tcp_state = TCP_CLOSED;
#endif
        }

        net_init_loop();
}

/**********************************************************************/
/*
 *      Main network processing loop.
 */

int net_loop(enum proto_t protocol)
{
        int ret = -EINVAL;

        net_restarted = 0;
        net_dev_exists = 0;
        net_try_count = 1;
        debug_cond(DEBUG_INT_STATE, "--- net_loop Entry\n");

        bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
        net_init();
        if (eth_is_on_demand_init() || protocol != NETCONS) {
                eth_halt();
                eth_set_current();
                ret = eth_init();
                if (ret < 0) {
                        eth_halt();
                        return ret;
                }
        } else {
                eth_init_state_only();
        }
restart:
#ifdef CONFIG_USB_KEYBOARD
        net_busy_flag = 0;
#endif
        net_set_state(NETLOOP_CONTINUE);

        /*
         *      Start the ball rolling with the given start function.  From
         *      here on, this code is a state machine driven by received
         *      packets and timer events.
         */
        debug_cond(DEBUG_INT_STATE, "--- net_loop Init\n");
        net_init_loop();

        switch (net_check_prereq(protocol)) {
        case 1:
                /* network not configured */
                eth_halt();
                return -ENODEV;

        case 2:
                /* network device not configured */
                break;

        case 0:
                net_dev_exists = 1;
                net_boot_file_size = 0;
                switch (protocol) {
                case TFTPGET:
#ifdef CONFIG_CMD_TFTPPUT
                case TFTPPUT:
#endif
                        /* always use ARP to get server ethernet address */
                        tftp_start(protocol);
                        break;
#ifdef CONFIG_CMD_TFTPSRV
                case TFTPSRV:
                        tftp_start_server();
                        break;
#endif
#if defined(CONFIG_CMD_DHCP)
                case DHCP:
                        bootp_reset();
                        net_ip.s_addr = 0;
                        dhcp_request();         /* Basically same as BOOTP */
                        break;
#endif

                case BOOTP:
                        bootp_reset();
                        net_ip.s_addr = 0;
                        bootp_request();
                        break;

#if defined(CONFIG_CMD_RARP)
                case RARP:
                        rarp_try = 0;
                        net_ip.s_addr = 0;
                        rarp_request();
                        break;
#endif
#if defined(CONFIG_CMD_PING)
                case PING:
                        ping_start();
                        break;
#endif
#if defined(CONFIG_CMD_NFS)
                case NFS:
                        nfs_start();
                        break;
#endif
#if defined(CONFIG_CMD_CDP)
                case CDP:
                        cdp_start();
                        break;
#endif
#if defined(CONFIG_NETCONSOLE) && !(CONFIG_SPL_BUILD)
                case NETCONS:
                        nc_start();
                        break;
#endif
#if defined(CONFIG_CMD_SNTP)
                case SNTP:
                        sntp_start();
                        break;
#endif
#if defined(CONFIG_CMD_DNS)
                case DNS:
                        dns_start();
                        break;
#endif
#if defined(CONFIG_CMD_LINK_LOCAL)
                case LINKLOCAL:
                        link_local_start();
                        break;
#endif
#ifdef TCP
//#if defined(CONFIG_CMD_WGET)
                case WGET:
                        wget_start();
                        break;
//#endif
#endif

                default:
                        break;
                }

                break;
        }

#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
#if     defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)        && \
        defined(CONFIG_STATUS_LED)                      && \
        defined(STATUS_LED_RED)
        /*
         * Echo the inverted link state to the fault LED.
         */
        if (miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR))
                status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
        else
                status_led_set(STATUS_LED_RED, STATUS_LED_ON);
#endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
#endif /* CONFIG_MII, ... */
#ifdef CONFIG_USB_KEYBOARD
        net_busy_flag = 1;
#endif

        /*
         *      Main packet reception loop.  Loop receiving packets until
         *      someone sets `net_state' to a state that terminates.
         */
        for (;;) {
                WATCHDOG_RESET();
#ifdef CONFIG_SHOW_ACTIVITY
                show_activity(1);
#endif
                if (arp_timeout_check() > 0)
                        time_start = get_timer(0);

                /*
                 *      Check the ethernet for a new packet.  The ethernet
                 *      receive routine will process it.
                 *      Most drivers return the most recent packet size, but not
                 *      errors that may have happened.
                 */
                eth_rx();

                /*
                 *      Abort if ctrl-c was pressed.
                 */
                if (ctrlc()) {
                        /* cancel any ARP that may not have completed */
                        net_arp_wait_packet_ip.s_addr = 0;

                        net_cleanup_loop();
                        eth_halt();
                        /* Invalidate the last protocol */
                        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");
                        ret = -EINTR;
                        goto done;
                }

                /*
                 *      Check for a timeout, and run the timeout handler
                 *      if we have one.
                 */
                if (time_handler &&
                    ((get_timer(0) - time_start) > time_delta)) {
                        thand_f *x;

#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
#if     defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)        && \
        defined(CONFIG_STATUS_LED)                      && \
        defined(STATUS_LED_RED)
                        /*
                         * Echo the inverted link state to the fault LED.
                         */
                        if (miiphy_link(eth_get_dev()->name,
                                        CONFIG_SYS_FAULT_MII_ADDR))
                                status_led_set(STATUS_LED_RED, STATUS_LED_OFF);
                        else
                                status_led_set(STATUS_LED_RED, STATUS_LED_ON);
#endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
#endif /* CONFIG_MII, ... */
                        debug_cond(DEBUG_INT_STATE, "--- net_loop timeout\n");
                        x = time_handler;
                        time_handler = (thand_f *)0;
                        (*x)();
                }

                if (net_state == NETLOOP_FAIL)
                        ret = net_start_again();

                switch (net_state) {
                case NETLOOP_RESTART:
                        net_restarted = 1;
                        goto restart;

                case NETLOOP_SUCCESS:
                        net_cleanup_loop();
                        if (net_boot_file_size > 0) {
                                printf("Bytes transferred = %d (%x hex)\n",
                                       net_boot_file_size, net_boot_file_size);
                                setenv_hex("filesize", net_boot_file_size);
                                setenv_hex("fileaddr", load_addr);
                        }
                        if (protocol != NETCONS)
                                eth_halt();
                        else
                                eth_halt_state_only();

                        eth_set_last_protocol(protocol);

                        ret = net_boot_file_size;
                        debug_cond(DEBUG_INT_STATE, "--- net_loop Success!\n");
                        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");
                        goto done;

                case NETLOOP_CONTINUE:
                        continue;
                }
        }

done:
#ifdef CONFIG_USB_KEYBOARD
        net_busy_flag = 0;
#endif
#ifdef CONFIG_CMD_TFTPPUT
        /* Clear out the handlers */
        net_set_udp_handler(NULL);
        net_set_icmp_handler(NULL);
#endif
        return ret;
}

/**********************************************************************/

static void start_again_timeout_handler(void)
{
        net_set_state(NETLOOP_RESTART);
}

int net_start_again(void)
{
        char *nretry;
        int retry_forever = 0;
        unsigned long retrycnt = 0;
        int ret;

        nretry = getenv("netretry");
        if (nretry) {
                if (!strcmp(nretry, "yes"))
                        retry_forever = 1;
                else if (!strcmp(nretry, "no"))
                        retrycnt = 0;
                else if (!strcmp(nretry, "once"))
                        retrycnt = 1;
                else
                        retrycnt = simple_strtoul(nretry, NULL, 0);
        } else {
                retrycnt = 0;
                retry_forever = 0;
        }

        if ((!retry_forever) && (net_try_count >= retrycnt)) {
                eth_halt();
                net_set_state(NETLOOP_FAIL);
                /*
                 * We don't provide a way for the protocol to return an error,
                 * but this is almost always the reason.
                 */
                return -ETIMEDOUT;
        }

        net_try_count++;

        eth_halt();
#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
        eth_try_another(!net_restarted);
#endif
        ret = eth_init();
        if (net_restart_wrap) {
                net_restart_wrap = 0;
                if (net_dev_exists) {
                        net_set_timeout_handler(10000UL,
                                                start_again_timeout_handler);
                        net_set_udp_handler(NULL);
                } else {
                        net_set_state(NETLOOP_FAIL);
                }
        } else {
                net_set_state(NETLOOP_RESTART);
        }
        return ret;
}

/**********************************************************************/
/*
 *      Miscelaneous bits.
 */

static void dummy_handler(uchar *pkt, unsigned dport,
                        struct in_addr sip, unsigned sport,
                        unsigned len)
{
}

rxhand_f *net_get_udp_handler(void)
{
        return udp_packet_handler;
}

void    net_set_tcp_handler(rxhand_f *f)
{
        debug_cond(DEBUG_INT_STATE, "--- net_loop TCP handler set (%p)\n", f);
        if (f == NULL)
                tcp_packet_handler = dummy_handler;
        else
                tcp_packet_handler = f;

}

void net_set_udp_handler(rxhand_f *f)
{
        debug_cond(DEBUG_INT_STATE, "--- net_loop UDP handler set (%p)\n", f);
        if (f == NULL)
                udp_packet_handler = dummy_handler;
        else
                udp_packet_handler = f;
}

rxhand_f *net_get_arp_handler(void)
{
        return arp_packet_handler;
}

void net_set_arp_handler(rxhand_f *f)
{
        debug_cond(DEBUG_INT_STATE, "--- net_loop ARP handler set (%p)\n", f);
        if (f == NULL)
                arp_packet_handler = dummy_handler;
        else
                arp_packet_handler = f;
}

#ifdef CONFIG_CMD_TFTPPUT
void net_set_icmp_handler(rxhand_icmp_f *f)
{
        packet_icmp_handler = f;
}
#endif

void net_set_timeout_handler(ulong iv, thand_f *f)
{
        if (iv == 0) {
                debug_cond(DEBUG_INT_STATE,
                           "--- net_loop timeout handler cancelled\n");
                time_handler = (thand_f *)0;
        } else {
                debug_cond(DEBUG_INT_STATE,
                           "--- net_loop timeout handler set (%p)\n", f);
                time_handler = f;
                time_start = get_timer(0);
                time_delta = iv * CONFIG_SYS_HZ / 1000;
        }
}

int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport,
                int payload_len)
{
//      net_send_udp_orig_packet( ether, dest, dport, sport, payload_len );
//      return(0);
        net_set_ports( dport, sport );
        return(net_send_ip_packet( payload_len, IPPROTO_UDP, IPPROTO_UDP, 0, 
0));
}


#ifdef CONFIG_IP_DEFRAG
/*
 * This function collects fragments in a single packet, according
 * to the algorithm in RFC815. It returns NULL or the pointer to
 * a complete packet, in static storage
 */
#ifndef CONFIG_NET_MAXDEFRAG
#define CONFIG_NET_MAXDEFRAG 16384
#endif
#define IP_PKTSIZE (CONFIG_NET_MAXDEFRAG)

#define IP_MAXUDP (IP_PKTSIZE - IP_HDR_SIZE)

/*
 * this is the packet being assembled, either data or frag control.
 * Fragments go by 8 bytes, so this union must be 8 bytes long
 */
struct hole {
        /* first_byte is address of this structure */
        u16 last_byte;  /* last byte in this hole + 1 (begin of next hole) */
        u16 next_hole;  /* index of next (in 8-b blocks), 0 == none */
        u16 prev_hole;  /* index of prev, 0 == none */
        u16 unused;
};

static struct ip_udp_hdr *__net_defragment(struct ip_udp_hdr *ip, int *lenp)
{
        static uchar pkt_buff[IP_PKTSIZE] __aligned(PKTALIGN);
        static u16 first_hole, total_len;
        struct hole *payload, *thisfrag, *h, *newh;
        struct ip_udp_hdr *localip = (struct ip_udp_hdr *)pkt_buff;
        uchar *indata = (uchar *)ip;
        int offset8, start, len, done = 0;
        u16 ip_off = ntohs(ip->ip_off);

        /* payload starts after IP header, this fragment is in there */
        payload = (struct hole *)(pkt_buff + IP_HDR_SIZE);
        offset8 =  (ip_off & IP_OFFS);
        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;

        if (!total_len || localip->ip_id != ip->ip_id) {
                /* new (or different) packet, reset structs */
                total_len = 0xffff;
                payload[0].last_byte = ~0;
                payload[0].next_hole = 0;
                payload[0].prev_hole = 0;
                first_hole = 0;
                /* any IP header will work, copy the first we received */
                memcpy(localip, ip, IP_HDR_SIZE);
        }

        /*
         * What follows is the reassembly algorithm. We use the payload
         * array as a linked list of hole descriptors, as each hole starts
         * at a multiple of 8 bytes. However, last byte can be whatever value,
         * so it is represented as byte count, not as 8-byte blocks.
         */

        h = payload + first_hole;
        while (h->last_byte < start) {
                if (!h->next_hole) {
                        /* no hole that far away */
                        return NULL;
                }
                h = payload + h->next_hole;
        }

        /* last fragment may be 1..7 bytes, the "+7" forces acceptance */
        if (offset8 + ((len + 7) / 8) <= h - payload) {
                /* no overlap with holes (dup fragment?) */
                return NULL;
        }

        if (!(ip_off & IP_FLAGS_MFRAG)) {
                /* no more fragmentss: truncate this (last) hole */
                total_len = start + len;
                h->last_byte = start + len;
        }

        /*
         * There is some overlap: fix the hole list. This code doesn't
         * deal with a fragment that overlaps with two different holes
         * (thus being a superset of a previously-received fragment).
         */

        if ((h >= thisfrag) && (h->last_byte <= start + len)) {
                /* complete overlap with hole: remove hole */
                if (!h->prev_hole && !h->next_hole) {
                        /* last remaining hole */
                        done = 1;
                } else if (!h->prev_hole) {
                        /* first hole */
                        first_hole = h->next_hole;
                        payload[h->next_hole].prev_hole = 0;
                } else if (!h->next_hole) {
                        /* last hole */
                        payload[h->prev_hole].next_hole = 0;
                } else {
                        /* in the middle of the list */
                        payload[h->next_hole].prev_hole = h->prev_hole;
                        payload[h->prev_hole].next_hole = h->next_hole;
                }

        } else if (h->last_byte <= start + len) {
                /* overlaps with final part of the hole: shorten this hole */
                h->last_byte = start;

        } else if (h >= thisfrag) {
                /* overlaps with initial part of the hole: move this hole */
                newh = thisfrag + (len / 8);
                *newh = *h;
                h = newh;
                if (h->next_hole)
                        payload[h->next_hole].prev_hole = (h - payload);
                if (h->prev_hole)
                        payload[h->prev_hole].next_hole = (h - payload);
                else
                        first_hole = (h - payload);

        } else {
                /* fragment sits in the middle: split the hole */
                newh = thisfrag + (len / 8);
                *newh = *h;
                h->last_byte = start;
                h->next_hole = (newh - payload);
                newh->prev_hole = (h - payload);
                if (newh->next_hole)
                        payload[newh->next_hole].prev_hole = (newh - payload);
        }

        /* finally copy this fragment and possibly return whole packet */
        memcpy((uchar *)thisfrag, indata + IP_HDR_SIZE, len);
        if (!done)
                return NULL;

        localip->ip_len = htons(total_len);
        *lenp = total_len + IP_HDR_SIZE;
        return localip;
}

static inline struct ip_udp_hdr *net_defragment(struct ip_udp_hdr *ip,
        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);
}

#else /* !CONFIG_IP_DEFRAG */

static inline struct ip_udp_hdr *net_defragment(struct ip_udp_hdr *ip,
        int *lenp)
{
        u16 ip_off = ntohs(ip->ip_off);
        if (!(ip_off & (IP_OFFS | IP_FLAGS_MFRAG)))
                return ip; /* not a fragment */
        return NULL;
}
#endif

/**
 * Receive an ICMP packet. We deal with REDIRECT and PING here, and silently
 * drop others.
 *
 * @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 icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src;

        switch (icmph->type) {
        case ICMP_REDIRECT:
                if (icmph->code != ICMP_REDIR_HOST)
                        return;
                printf(" ICMP Host Redirect to %pI4 ",
                       &icmph->un.gateway);
                break;
        default:
#if defined(CONFIG_CMD_PING)
                ping_receive(et, ip, len);
#endif
#ifdef CONFIG_CMD_TFTPPUT
                if (packet_icmp_handler)
                        packet_icmp_handler(icmph->type, icmph->code,
                                            ntohs(ip->udp_dst), src_ip,
                                            ntohs(ip->udp_src), icmph->un.data,
                                            ntohs(ip->udp_len));
#endif
                break;
        }
}

void net_process_received_packet(uchar *in_packet, int len)
{
        struct ethernet_hdr *et;
        struct ip_udp_hdr *ip;
        struct in_addr dst_ip;
        struct in_addr src_ip;
        int eth_proto;
#if defined(CONFIG_CMD_CDP)
        int iscdp;
#endif
        ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;

        debug_cond(DEBUG_NET_PKT, "packet received\n");

        net_rx_packet = in_packet;
        net_rx_packet_len = len;
        et = (struct ethernet_hdr *)in_packet;

        /* too small packet? */
        if (len < ETHER_HDR_SIZE)
                return;

#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
        if (push_packet) {
                (*push_packet)(in_packet, len);
                return;
        }
#endif

#if defined(CONFIG_CMD_CDP)
        /* keep track if packet is CDP */
        iscdp = is_cdp_packet(et->et_dest);
#endif

        myvlanid = ntohs(net_our_vlan);
        if (myvlanid == (ushort)-1)
                myvlanid = VLAN_NONE;
        mynvlanid = ntohs(net_native_vlan);
        if (mynvlanid == (ushort)-1)
                mynvlanid = VLAN_NONE;

        eth_proto = ntohs(et->et_protlen);

        if (eth_proto < 1514) {
                struct e802_hdr *et802 = (struct e802_hdr *)et;
                /*
                 *      Got a 802.2 packet.  Check the other protocol field.
                 *      XXX VLAN over 802.2+SNAP not implemented!
                 */
                eth_proto = ntohs(et802->et_prot);

                ip = (struct ip_udp_hdr *)(in_packet + E802_HDR_SIZE);
                len -= E802_HDR_SIZE;

        } else if (eth_proto != PROT_VLAN) {    /* normal packet */
                ip = (struct ip_udp_hdr *)(in_packet + ETHER_HDR_SIZE);
                len -= ETHER_HDR_SIZE;

        } else {                        /* VLAN packet */
                struct vlan_ethernet_hdr *vet =
                        (struct vlan_ethernet_hdr *)et;

                debug_cond(DEBUG_NET_PKT, "VLAN packet received\n");

                /* too small packet? */
                if (len < VLAN_ETHER_HDR_SIZE)
                        return;

                /* if no VLAN active */
                if ((ntohs(net_our_vlan) & VLAN_IDMASK) == VLAN_NONE
#if defined(CONFIG_CMD_CDP)
                                && iscdp == 0
#endif
                                )
                        return;

                cti = ntohs(vet->vet_tag);
                vlanid = cti & VLAN_IDMASK;
                eth_proto = ntohs(vet->vet_type);

                ip = (struct ip_udp_hdr *)(in_packet + VLAN_ETHER_HDR_SIZE);
                len -= VLAN_ETHER_HDR_SIZE;
        }

        debug_cond(DEBUG_NET_PKT, "Receive from protocol 0x%x\n", eth_proto);

#if defined(CONFIG_CMD_CDP)
        if (iscdp) {
                cdp_receive((uchar *)ip, len);
                return;
        }
#endif

        if ((myvlanid & VLAN_IDMASK) != VLAN_NONE) {
                if (vlanid == VLAN_NONE)
                        vlanid = (mynvlanid & VLAN_IDMASK);
                /* not matched? */
                if (vlanid != (myvlanid & VLAN_IDMASK))
                        return;
        }

        switch (eth_proto) {
        case PROT_ARP:
                arp_receive(et, ip, len);
                break;

#ifdef CONFIG_CMD_RARP
        case PROT_RARP:
                rarp_receive(ip, len);
                break;
#endif
        case PROT_IP:
                debug_cond(DEBUG_NET_PKT, "Got IP\n");
                /* Before we start poking the header, make sure it is there */
                if (len < IP_UDP_HDR_SIZE) {
                        debug("len bad %d < %lu\n", len,
                              (ulong)IP_UDP_HDR_SIZE);
                        return;
                }
                /* Check the packet length */
                if (len < ntohs(ip->ip_len)) {
                        debug("len bad %d < %d\n", len, ntohs(ip->ip_len));
                        return;
                }
                len = ntohs(ip->ip_len);
                debug_cond(DEBUG_NET_PKT, "len=%d, v=%02x\n",
                           len, ip->ip_hl_v & 0xff);

                /* 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");
                        return;
                }
                /* If it is not for us, ignore it */
                dst_ip = net_read_ip(&ip->ip_dst);
                if (net_ip.s_addr && dst_ip.s_addr != net_ip.s_addr &&
                    dst_ip.s_addr != 0xFFFFFFFF) {
#ifdef CONFIG_MCAST_TFTP
                        if (net_mcast_addr != dst_ip)
#endif
                                return;
                }
                /* Read source IP address for later use */
                src_ip = net_read_ip(&ip->ip_src);
                /*
                 * The function returns the unchanged packet if it's not
                 * a fragment, and either the complete packet or NULL if
                 * it is a fragment (if !CONFIG_IP_DEFRAG, it returns NULL)
                 */
                ip = net_defragment(ip, &len);
                if (!ip)
                        return;
                /*
                 * watch for ICMP host redirects
                 *
                 * There is no real handler code (yet). We just watch
                 * for ICMP host redirect messages. In case anybody
                 * sees these messages: please contact me
                 * (w...@denx.de), or - even better - send me the
                 * necessary fixes :-)
                 *
                 * Note: in all cases where I have seen this so far
                 * it was a problem with the router configuration,
                 * for instance when a router was configured in the
                 * BOOTP reply, but the TFTP server was on the same
                 * subnet. So this is probably a warning that your
                 * configuration might be wrong. But I'm not really
                 * sure if there aren't any other situations.
                 *
                 * Simon Glass <s...@chromium.org>: We get an ICMP when
                 * we send a tftp packet to a dead connection, or when
                 * there is no server at the other end.
                 */
                if (ip->ip_p == IPPROTO_ICMP) {
                        receive_icmp(ip, len, src_ip, et);
                        return;
                } else if (ip->ip_p == IPPROTO_UDP) {   /* Only UDP packets */

                        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) +
                                               ((xsum >> 16) & 0x0000ffff);
                                }
                                if ((xsum != 0x00000000) && (xsum != 
0x0000ffff)) {
                                        printf(" UDP wrong checksum %08lx 
%08x\n",
                                               xsum, ntohs(ip->udp_xsum));
                                        return;
                                }
                        }
#endif

#if defined(CONFIG_NETCONSOLE) && !(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);
#endif
                        /*
                        * IP header OK.  Pass the packet to the current handler.
                        */
                        debug_cond(DEBUG_DEV_PKT,
                           "UDP PH (to=%pI4, from=%pI4, len=%d)\n",
                           &dst_ip, &src_ip, len);
                        (*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);

                }
#ifdef 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

        }
}

/**********************************************************************/

static int net_check_prereq(enum proto_t protocol)
{
        switch (protocol) {
                /* Fall through */
#if defined(CONFIG_CMD_PING)
        case PING:
                if (net_ping_ip.s_addr == 0) {
                        puts("*** ERROR: ping address not given\n");
                        return 1;
                }
                goto common;
#endif
#if defined(CONFIG_CMD_SNTP)
        case SNTP:
                if (net_ntp_server.s_addr == 0) {
                        puts("*** ERROR: NTP server address not given\n");
                        return 1;
                }
                goto common;
#endif
#if defined(CONFIG_CMD_DNS)
        case DNS:
                if (net_dns_server.s_addr == 0) {
                        puts("*** ERROR: DNS server address not given\n");
                        return 1;
                }
                goto common;
#endif
#if defined(CONFIG_CMD_NFS)
        case NFS:
#endif
                /* Fall through */
        case TFTPGET:
        case TFTPPUT:
                if (net_server_ip.s_addr == 0) {
                        puts("*** ERROR: `serverip' not set\n");
                        return 1;
                }
#if     defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP) || \
        defined(CONFIG_CMD_DNS)
common:
#endif
                /* Fall through */

        case NETCONS:
        case TFTPSRV:
                if (net_ip.s_addr == 0) {
                        puts("*** ERROR: `ipaddr' not set\n");
                        return 1;
                }
                /* Fall through */

#ifdef CONFIG_CMD_RARP
        case RARP:
#endif
        case BOOTP:
        case CDP:
        case DHCP:
        case LINKLOCAL:
                if (memcmp(net_ethaddr, "\0\0\0\0\0\0", 6) == 0) {
                        int num = eth_get_dev_index();

                        switch (num) {
                        case -1:
                                puts("*** ERROR: No ethernet found.\n");
                                return 1;
                        case 0:
                                puts("*** ERROR: `ethaddr' not set\n");
                                break;
                        default:
                                printf("*** ERROR: `eth%daddr' not set\n",
                                       num);
                                break;
                        }

                        net_start_again();
                        return 2;
                }
                /* Fall through */
        default:
                return 0;
        }
        return 0;               /* OK */
}
/**********************************************************************/

int
net_eth_hdr_size(void)
{
        ushort myvlanid;

        myvlanid = ntohs(net_our_vlan);
        if (myvlanid == (ushort)-1)
                myvlanid = VLAN_NONE;

        return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE :
                VLAN_ETHER_HDR_SIZE;
}

int net_set_ether(uchar *xet, const uchar *dest_ethaddr, uint prot)
{
        struct ethernet_hdr *et = (struct ethernet_hdr *)xet;
        ushort myvlanid;

        myvlanid = ntohs(net_our_vlan);
        if (myvlanid == (ushort)-1)
                myvlanid = VLAN_NONE;

        memcpy(et->et_dest, dest_ethaddr, 6);
        memcpy(et->et_src, net_ethaddr, 6);
        if ((myvlanid & VLAN_IDMASK) == VLAN_NONE) {
                et->et_protlen = htons(prot);
                return ETHER_HDR_SIZE;
        } else {
                struct vlan_ethernet_hdr *vet =
                        (struct vlan_ethernet_hdr *)xet;

                vet->vet_vlan_type = htons(PROT_VLAN);
                vet->vet_tag = htons((0 << 5) | (myvlanid & VLAN_IDMASK));
                vet->vet_type = htons(prot);
                return VLAN_ETHER_HDR_SIZE;
        }
}

int net_update_ether(struct ethernet_hdr *et, uchar *addr, uint prot)
{
        ushort protlen;

        memcpy(et->et_dest, addr, 6);
        memcpy(et->et_src, net_ethaddr, 6);
        protlen = ntohs(et->et_protlen);
        if (protlen == PROT_VLAN) {
                struct vlan_ethernet_hdr *vet =
                        (struct vlan_ethernet_hdr *)et;
                vet->vet_type = htons(prot);
                return VLAN_ETHER_HDR_SIZE;
        } else if (protlen > 1514) {
                et->et_protlen = htons(prot);
                return ETHER_HDR_SIZE;
        } 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,
                                                u16  pkt_len, u8 prot)
{
        struct ip_hdr *ip = (struct ip_hdr *)pkt;

        /*
         *      Construct an IP header.
         */
        /* IP_HDR_SIZE / 4 (not including UDP) */
        ip->ip_hl_v  = 0x45;
        ip->ip_tos   = 0;
        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)
{
        struct ip_udp_hdr *ip = (struct ip_udp_hdr *)pkt;

        /*
         *      If the data is an odd number of bytes, zero the
         *      byte after the last byte so that the checksum
         *      will work.
         */
        if (len & 1)
                pkt[IP_UDP_HDR_SIZE + len] = 0;

        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);
        ip->udp_len  = htons(UDP_HDR_SIZE + len);
        ip->udp_xsum = 0;
}

void copy_filename(char *dst, const char *src, int size)
{
        if (*src && (*src == '"')) {
                ++src;
                --size;
        }

        while ((--size > 0) && *src && (*src != '"'))
                *dst++ = *src++;
        *dst = '\0';
}

#if     defined(CONFIG_CMD_NFS)         || \
        defined(CONFIG_CMD_SNTP)        || \
        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
 * all supported protocols/clients/servers
 */
unsigned int random_port(void)
{
        return 1024 + (get_timer(0) % 0x4000);
}
#endif

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)
        );
}

void vlan_to_string(ushort x, char *s)
{
        x = ntohs(x);

        if (x == (ushort)-1)
                x = VLAN_NONE;

        if (x == VLAN_NONE)
                strcpy(s, "none");
        else
                sprintf(s, "%d", x & VLAN_IDMASK);
}

ushort string_to_vlan(const char *s)
{
        ushort id;

        if (s == NULL)
                return htons(VLAN_NONE);

        if (*s < '0' || *s > '9')
                id = VLAN_NONE;
        else
                id = (ushort)simple_strtoul(s, NULL, 10);

        return htons(id);
}

ushort getenv_vlan(char *var)
{
        return string_to_vlan(getenv(var));
}include/net.h
 /*
 *      LiMon Monitor (LiMon) - Network.
 *
 *      Copyright 1994 - 2000 Neil Russell.
 *      (See License)
 *      SPDX-License-Identifier:        GPL-2.0
 *
 * History
 *      9/16/00   bor  adapted to TQM823L/STK8xxL board, RARP/TFTP boot added
 *      9/20/2017 dch   Added TCP listener
 */

#ifndef __NET_H__
#define __NET_H__

#if defined(CONFIG_8xx)
#include <commproc.h>
#endif  /* CONFIG_8xx */

#include <asm/cache.h>
#include <asm/byteorder.h>      /* for nton* / ntoh* stuff */
#define DEBUG_LL_STATE 0        /* Link local state machine changes */
#define DEBUG_DEV_PKT 0         /* Packets or info directed to the device */
#define DEBUG_NET_PKT 0         /* Packets on info on the network at large */
#define DEBUG_INT_STATE 0       /* Internal network state changes */

/*
 *      The number of receive packet buffers, and the required packet buffer
 *      alignment in memory.
 *
 */

#define TCP 1

#ifdef TCP
#define CONFIG_SYS_RX_ETH_BUFFER 50     /* For TCP */
#endif

#ifdef CONFIG_SYS_RX_ETH_BUFFER
# define PKTBUFSRX      CONFIG_SYS_RX_ETH_BUFFER
#else
# define PKTBUFSRX      4
#endif

#define PKTALIGN        ARCH_DMA_MINALIGN

/* IPv4 addresses are always 32 bits in size */
struct in_addr {
        __be32 s_addr;
};

/**
 * An incoming packet handler.
 * @param pkt    pointer to the application packet
 * @param dport  destination UDP port
 * @param sip    source IP address
 * @param sport  source UDP port
 * @param len    packet length
 */
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
 * @param dport destination UDP port
 * @param sip   source IP address
 * @param sport source UDP port
 * @param pkt   pointer to the ICMP packet data
 * @param len   packet length
 */
typedef void rxhand_icmp_f(unsigned type, unsigned code, unsigned dport,
                struct in_addr sip, unsigned sport, uchar *pkt, unsigned len);

/*
 *      A timeout handler.  Called after time interval has expired.
 */
typedef void    thand_f(void);

enum eth_state_t {
        ETH_STATE_INIT,
        ETH_STATE_PASSIVE,
        ETH_STATE_ACTIVE
};

#ifdef CONFIG_DM_ETH
/**
 * struct eth_pdata - Platform data for Ethernet MAC controllers
 *
 * @iobase: The base address of the hardware registers
 * @enetaddr: The Ethernet MAC address that is loaded from EEPROM or env
 * @phy_interface: PHY interface to use - see PHY_INTERFACE_MODE_...
 * @max_speed: Maximum speed of Ethernet connection supported by MAC
 */
struct eth_pdata {
        phys_addr_t iobase;
        unsigned char enetaddr[6];
        int phy_interface;
        int max_speed;
};

enum eth_recv_flags {
        /*
         * Check hardware device for new packets (otherwise only return those
         * which are already in the memory buffer ready to process)
         */
        ETH_RECV_CHECK_DEVICE           = 1 << 0,
};

/**
 * struct eth_ops - functions of Ethernet MAC controllers
 *
 * start: Prepare the hardware to send and receive packets
 * send: Send the bytes passed in "packet" as a packet on the wire
 * recv: Check if the hardware received a packet. If so, set the pointer to the
 *       packet buffer in the packetp parameter. If not, return an error or 0 to
 *       indicate that the hardware receive FIFO is empty. If 0 is returned, the
 *       network stack will not process the empty packet, but free_pkt() will be
 *       called if supplied
 * free_pkt: Give the driver an opportunity to manage its packet buffer memory
 *           when the network stack is finished processing it. This will only be
 *           called when no error was returned from recv - optional
 * stop: Stop the hardware from looking for packets - may be called even if
 *       state == PASSIVE
 * mcast: Join or leave a multicast group (for TFTP) - optional
 * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux
 *               on some platforms like ARM). This function expects the
 *               eth_pdata::enetaddr field to be populated. The method can
 *               return -ENOSYS to indicate that this is not implemented for
                 this hardware - optional.
 * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a
 *                  ROM on the board. This is how the driver should expose it
 *                  to the network stack. This function should fill in the
 *                  eth_pdata::enetaddr field - optional
 */
struct eth_ops {
        int (*start)(struct udevice *dev);
        int (*send)(struct udevice *dev, void *packet, int length);
        int (*recv)(struct udevice *dev, int flags, uchar **packetp);
        int (*free_pkt)(struct udevice *dev, uchar *packet, int length);
        void (*stop)(struct udevice *dev);
#ifdef CONFIG_MCAST_TFTP
        int (*mcast)(struct udevice *dev, const u8 *enetaddr, int join);
#endif
        int (*write_hwaddr)(struct udevice *dev);
        int (*read_rom_hwaddr)(struct udevice *dev);
};

#define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)

struct udevice *eth_get_dev(void); /* get the current device */
/*
 * The devname can be either an exact name given by the driver or device tree
 * or it can be an alias of the form "eth%d"
 */
struct udevice *eth_get_dev_by_name(const char *devname);
unsigned char *eth_get_ethaddr(void); /* get the current device MAC */

/* Used only when NetConsole is enabled */
int eth_is_active(struct udevice *dev); /* Test device for active state */
int eth_init_state_only(void); /* Set active state */
void eth_halt_state_only(void); /* Set passive state */
#endif

#ifndef CONFIG_DM_ETH
struct eth_device {
        char name[16];
        unsigned char enetaddr[6];
        phys_addr_t iobase;
        int state;

        int (*init)(struct eth_device *, bd_t *);
        int (*send)(struct eth_device *, void *packet, int length);
        int (*recv)(struct eth_device *);
        void (*halt)(struct eth_device *);
#ifdef CONFIG_MCAST_TFTP
        int (*mcast)(struct eth_device *, const u8 *enetaddr, u8 set);
#endif
        int (*write_hwaddr)(struct eth_device *);
        struct eth_device *next;
        int index;
        void *priv;
};

int eth_register(struct eth_device *dev);/* Register network device */
int eth_unregister(struct eth_device *dev);/* Remove network device */

extern struct eth_device *eth_current;

static __always_inline struct eth_device *eth_get_dev(void)
{
        return eth_current;
}
struct eth_device *eth_get_dev_by_name(const char *devname);
struct eth_device *eth_get_dev_by_index(int index); /* get dev @ index */

/* get the current device MAC */
static inline unsigned char *eth_get_ethaddr(void)
{
        if (eth_current)
                return eth_current->enetaddr;
        return NULL;
}

/* Used only when NetConsole is enabled */
int eth_is_active(struct eth_device *dev); /* Test device for active state */
/* Set active state */
static __always_inline int eth_init_state_only(void)
{
        eth_get_dev()->state = ETH_STATE_ACTIVE;

        return 0;
}
/* Set passive state */
static __always_inline void eth_halt_state_only(void)
{
        eth_get_dev()->state = ETH_STATE_PASSIVE;
}

/*
 * Set the hardware address for an ethernet interface based on 'eth%daddr'
 * environment variable (or just 'ethaddr' if eth_number is 0).
 * Args:
 *      base_name - base name for device (normally "eth")
 *      eth_number - value of %d (0 for first device of this type)
 * Returns:
 *      0 is success, non-zero is error status from driver.
 */
int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
                     int eth_number);

int usb_eth_initialize(bd_t *bi);
#endif

int eth_initialize(void);               /* Initialize network subsystem */
void eth_try_another(int first_restart);        /* Change the device */
void eth_set_current(void);             /* set nterface to ethcur var */

int eth_get_dev_index(void);            /* get the device index */
void eth_parse_enetaddr(const char *addr, uchar *enetaddr);
int eth_getenv_enetaddr(const char *name, uchar *enetaddr);
int eth_setenv_enetaddr(const char *name, const uchar *enetaddr);

/**
 * eth_setenv_enetaddr_by_index() - set the MAC address environment variable
 *
 * This sets up an environment variable with the given MAC address (@enetaddr).
 * The environment variable to be set is defined by <@base_name><@index>addr.
 * If @index is 0 it is omitted. For common Ethernet this means ethaddr,
 * eth1addr, etc.
 *
 * @base_name:  Base name for variable, typically "eth"
 * @index:      Index of interface being updated (>=0)
 * @enetaddr:   Pointer to MAC address to put into the variable
 * @return 0 if OK, other value on error
 */
int eth_setenv_enetaddr_by_index(const char *base_name, int index,
                                 uchar *enetaddr);


/*
 * Get the hardware address for an ethernet interface .
 * Args:
 *      base_name - base name for device (normally "eth")
 *      index - device index number (0 for first)
 *      enetaddr - returns 6 byte hardware address
 * Returns:
 *      Return true if the address is valid.
 */
int eth_getenv_enetaddr_by_index(const char *base_name, int index,
                                 uchar *enetaddr);

int eth_init(void);                     /* Initialize the device */
int eth_send(void *packet, int length);    /* Send a packet */

#if defined(CONFIG_API) || defined(CONFIG_EFI_LOADER)
int eth_receive(void *packet, int length); /* Receive a packet*/
extern void (*push_packet)(void *packet, int length);
#endif
int eth_rx(void);                       /* Check for received packets */
void eth_halt(void);                    /* stop SCC */
const char *eth_get_name(void);         /* get name of current device */

#ifdef CONFIG_MCAST_TFTP
int eth_mcast_join(struct in_addr mcast_addr, int join);
u32 ether_crc(size_t len, unsigned char const *p);
#endif


/**********************************************************************/
/*
 *      Protocol headers.
 */

/*
 *      Ethernet header
 */

struct ethernet_hdr {
        u8              et_dest[6];     /* Destination node             */
        u8              et_src[6];      /* Source node                  */
        u16             et_protlen;     /* Protocol or length           */
};

/* Ethernet header size */
#define ETHER_HDR_SIZE  (sizeof(struct ethernet_hdr))

#define ETH_FCS_LEN     4               /* Octets in the FCS            */

struct e802_hdr {
        u8              et_dest[6];     /* Destination node             */
        u8              et_src[6];      /* Source node                  */
        u16             et_protlen;     /* Protocol or length           */
        u8              et_dsap;        /* 802 DSAP                     */
        u8              et_ssap;        /* 802 SSAP                     */
        u8              et_ctl;         /* 802 control                  */
        u8              et_snap1;       /* SNAP                         */
        u8              et_snap2;
        u8              et_snap3;
        u16             et_prot;        /* 802 protocol                 */
}__attribute__ ((packed));

/* 802 + SNAP + ethernet header size */
#define E802_HDR_SIZE   (sizeof(struct e802_hdr))

/*
 *      Virtual LAN Ethernet header
 */
struct vlan_ethernet_hdr {
        u8              vet_dest[6];    /* Destination node             */
        u8              vet_src[6];     /* Source node                  */
        u16             vet_vlan_type;  /* PROT_VLAN                    */
        u16             vet_tag;        /* TAG of VLAN                  */
        u16             vet_type;       /* protocol type                */
}__attribute__ ((packed));


/* VLAN Ethernet header size */
#define VLAN_ETHER_HDR_SIZE     (sizeof(struct vlan_ethernet_hdr))

#define PROT_IP         0x0800          /* IP protocol                  */
#define PROT_ARP        0x0806          /* IP ARP protocol              */
#define PROT_RARP       0x8035          /* IP ARP protocol              */
#define PROT_VLAN       0x8100          /* IEEE 802.1q protocol         */
#define PROT_IPV6       0x86dd          /* IPv6 over bluebook           */
#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               */

/*
 *      Internet Protocol (IP) header.
 */
struct ip_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       */
}__attribute__ ((packed));

#define IP_OFFS         0x1fff /* ip offset *= 8 */
#define IP_FLAGS        0xe000 /* first 3 bits */
#define IP_FLAGS_RES    0x8000 /* reserved */
#define IP_FLAGS_DFRAG  0x4000 /* don't fragment */
#define IP_FLAGS_MFRAG  0x2000 /* more fragments */

#define IP_HDR_SIZE             (sizeof(struct ip_hdr))

/*
 *      Internet Protocol (IP) + UDP header.
 */
struct ip_udp_hdr {
        u8              ip_hl_v;        /* header length and version    */
        u8              ip_tos;         /* type of service              */
        u16             ip_len;         /* total length                 */
        u16             ip_id;          /* identification               */
                                        /* Flags first 3 bits of ip_off */
        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             udp_src;        /* UDP source port              */
        u16             udp_dst;        /* UDP destination port         */
        u16             udp_len;        /* Length of UDP packet         */
        u16             udp_xsum;       /* Checksum                     */
}__attribute__ ((packed));

#define IP_UDP_HDR_SIZE         (sizeof(struct ip_udp_hdr))
#define UDP_HDR_SIZE            (IP_UDP_HDR_SIZE - IP_HDR_SIZE)

/*
 *      Internet Protocol (IP) + TCP header.
*/
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 reserver         */
        u8              tcp_flags;      /* see defines                  */
        u16             tcp_win;        /* TCP windows size             */
        u16             tcp_xsum;       /* Checksum                     */
        u16             tcp_ugr;        /* Pointer to urgent data       */
}__attribute__ ((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       /* 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       /* Unknown                              */
#define TCP_CWR      0x80       /* Unknown                              */

/*
 * 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              /* TimestampLength              */



#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      */
}__attribute__ ((packed));

struct tcp_scale {                      /* TCP Windows Scale            */
        u8      kind;                   /* 0x03                         */
        u8      len;                    /* 0x03                         */
        u8      scale;                  /* win shift fat fast networks  */
}__attribute__ ((packed));

struct tcp_sack_p {                     /* SACK permitted               */
        u8      kind;                   /* 0x04                         */
        u8      len;                    /* Length                       */
}__attribute__ ((packed));

struct sack_edges {
        u32     l;
        u32     r;
}__attribute__ ((packed));

#define TCP_STREAM_HOLES                16

#define TCP_SAK_HOLES                   3

#define TCP_HOLE_AGE                    4

struct tcp_sack_v {
        u8      kind;                   /* 0x05                         */
        u8      len;                    /* Length                       */
        struct sack_edges hole[TCP_SAK_HOLES];  /* L & R widow edges    */
}__attribute__ ((packed));

struct tcp_TSopt{                       /* TCP time stamps option       */
        u8      kind;                   /* 0x08                         */
        u8      len;                    /* 0x0a                         */
        u32     TSsnd;                  /* Sender timestamp             */
        u32     TSrcv;                  /* Receiver timestamp           */
}__attribute__ ((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;
}__attribute__ ((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;
}__attribute__ ((packed));

#define IP_TCP_SACK_SIZE        (sizeof(struct ip_tcp_hdr_s))

/*
 * TCP psuedo header definitions
*/

struct psuedo_hdr{
        u8 padding[8];                  /* psuedo header size = ip_tcp hdr size 
*/
        struct in_addr p_src;
        struct in_addr p_dst;
        u8      rsvd;
        u8      p;
        u16     len;
}__attribute__ ((packed));

#define PSUEDO_PAD_SIZE         8
#define PSUEDO_HDR_SIZE         12

/*
 * 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];
}__attribute__ ((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,        /* both server and client represents an open 
connection */
        TCP_CLOSE_WAIT,         /* Received FIN, passed to app for FIN, ACK 
response    */
        TCP_CLOSING,            /* Received FIN, sent FIN, ACK waiting for ACK  
        */
        TCP_FIN_WAIT_1,         /* Sendt FIN waiting for response               
        */
        TCP_FIN_WAIT_2          /* Received ACK from FIN sent, waitng for FIN   
        */
};

enum TCP_STATE net_get_tcp_state( void );

/*
 *      TCP incoming packet handler
*/

typedef void rxhand_tcp(uchar *pkt, unsigned dport,
                        struct in_addr sip, unsigned sport,
                                unsigned len, enum TCP_STATE tcp_state);
/*
 *      Address Resolution Protocol (ARP) header.
 */
struct arp_hdr {
        u16             ar_hrd;         /* Format of hardware address   */
#   define ARP_ETHER        1           /* Ethernet  hardware address   */
        u16             ar_pro;         /* Format of protocol address   */
        u8              ar_hln;         /* Length of hardware address   */
#   define ARP_HLEN     6
        u8              ar_pln;         /* Length of protocol address   */
#   define ARP_PLEN     4
        u16             ar_op;          /* Operation                    */
#   define ARPOP_REQUEST    1           /* Request  to resolve  address */
#   define ARPOP_REPLY      2           /* Response to previous request */

#   define RARPOP_REQUEST   3           /* Request  to resolve  address */
#   define RARPOP_REPLY     4           /* Response to previous request */

        /*
         * The remaining fields are variable in size, according to
         * the sizes above, and are defined as appropriate for
         * specific hardware/protocol combinations.
         */
        u8              ar_data[0];
#define ar_sha          ar_data[0]
#define ar_spa          ar_data[ARP_HLEN]
#define ar_tha          ar_data[ARP_HLEN + ARP_PLEN]
#define ar_tpa          ar_data[ARP_HLEN + ARP_PLEN + ARP_HLEN]
#if 0
        u8              ar_sha[];       /* Sender hardware address      */
        u8              ar_spa[];       /* Sender protocol address      */
        u8              ar_tha[];       /* Target hardware address      */
        u8              ar_tpa[];       /* Target protocol address      */
#endif /* 0 */
};

#define ARP_HDR_SIZE    (8+20)          /* Size assuming ethernet       */

/*
 * ICMP stuff (just enough to handle (host) redirect messages)
 */
#define ICMP_ECHO_REPLY         0       /* Echo reply                   */
#define ICMP_NOT_REACH          3       /* Detination unreachable       */
#define ICMP_REDIRECT           5       /* Redirect (change route)      */
#define ICMP_ECHO_REQUEST       8       /* Echo request                 */

/* Codes for REDIRECT. */
#define ICMP_REDIR_NET          0       /* Redirect Net                 */
#define ICMP_REDIR_HOST         1       /* Redirect Host                */

/* Codes for NOT_REACH */
#define ICMP_NOT_REACH_PORT     3       /* Port unreachable             */

struct icmp_hdr {
        u8              type;
        u8              code;
        u16             checksum;
        union {
                struct {
                        u16     id;
                        u16     sequence;
                } echo;
                u32     gateway;
                struct {
                        u16     unused;
                        u16     mtu;
                } frag;
                u8 data[0];
        } un;
};

#define ICMP_HDR_SIZE           (sizeof(struct icmp_hdr))
#define IP_ICMP_HDR_SIZE        (IP_HDR_SIZE + ICMP_HDR_SIZE)

/*
 * Maximum packet size; used to allocate packet storage. Use
 * the maxium Ethernet frame size as specified by the Ethernet
 * standard including the 802.1Q tag (VLAN tagging).
 * maximum packet size =  1522
 * maximum packet size and multiple of 32 bytes =  1536
 */
#define PKTSIZE                 1522
#define PKTSIZE_ALIGN           1536

/*
 * Maximum receive ring size; that is, the number of packets
 * we can buffer before overflow happens. Basically, this just
 * needs to be enough to prevent a packet being discarded while
 * we are processing the previous one.
 */
#define RINGSZ          4
#define RINGSZ_LOG2     2

/**********************************************************************/
/*
 *      Globals.
 *
 * Note:
 *
 * All variables of type struct in_addr are stored in NETWORK byte order
 * (big endian).
 */

/* net.c */
/** BOOTP EXTENTIONS **/
extern struct in_addr net_gateway;      /* Our gateway IP address */
extern struct in_addr net_netmask;      /* Our subnet mask (0 = unknown) */
/* Our Domain Name Server (0 = unknown) */
extern struct in_addr net_dns_server;
#if defined(CONFIG_BOOTP_DNS2)
/* Our 2nd Domain Name Server (0 = unknown) */
extern struct in_addr net_dns_server2;
#endif
extern char     net_nis_domain[32];     /* Our IS domain */
extern char     net_hostname[32];       /* Our hostname */
extern char     net_root_path[64];      /* Our root path */
/** END OF BOOTP EXTENTIONS **/
extern u8               net_ethaddr[6];         /* Our ethernet address */
extern u8               net_server_ethaddr[6];  /* Boot server enet address */
extern struct in_addr   net_ip;         /* Our    IP addr (0 = unknown) */
extern struct in_addr   net_server_ip;  /* Server IP addr (0 = unknown) */
extern uchar            *net_tx_packet;         /* THE transmit packet */
extern uchar            *net_rx_packets[PKTBUFSRX]; /* Receive packets */
extern uchar            *net_rx_packet;         /* Current receive packet */
extern int              net_rx_packet_len;      /* Current rx packet length */
extern const u8         net_bcast_ethaddr[6];   /* Ethernet broadcast address */
extern const u8         net_null_ethaddr[6];

#define VLAN_NONE       4095                    /* untagged */
#define VLAN_IDMASK     0x0fff                  /* mask of valid vlan id */
extern ushort           net_our_vlan;           /* Our VLAN */
extern ushort           net_native_vlan;        /* Our Native VLAN */

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, WGET
};

extern char     net_boot_file_name[1024];/* Boot File name */
/* The actual transferred size of the bootfile (in bytes) */
extern u32      net_boot_file_size;
/* Boot file size in blocks as reported by the DHCP server */
extern u32      net_boot_file_expected_size_in_blocks;

#if defined(CONFIG_CMD_DNS)
extern char *net_dns_resolve;           /* The host to resolve  */
extern char *net_dns_env_var;           /* the env var to put the ip into */
#endif

#if defined(CONFIG_CMD_PING)
extern struct in_addr net_ping_ip;      /* the ip address to ping */
#endif

#if defined(CONFIG_CMD_CDP)
/* when CDP completes these hold the return values */
extern ushort cdp_native_vlan;          /* CDP returned native VLAN */
extern ushort cdp_appliance_vlan;       /* CDP returned appliance VLAN */

/*
 * Check for a CDP packet by examining the received MAC address field
 */
static inline int is_cdp_packet(const uchar *ethaddr)
{
        extern const u8 net_cdp_ethaddr[6];

        return memcmp(ethaddr, net_cdp_ethaddr, 6) == 0;
}
#endif

#if defined(CONFIG_CMD_SNTP)
extern struct in_addr   net_ntp_server;         /* the ip address to NTP */
extern int net_ntp_time_offset;                 /* offset time from UTC */
#endif

#if defined(CONFIG_MCAST_TFTP)
extern struct in_addr net_mcast_addr;
#endif

/* Initialize the network adapter */
void net_init(void);
int net_loop(enum proto_t);

/* Load failed.  Start again. */
int net_start_again(void);

/* Get size of the ethernet header when we send */
int net_eth_hdr_size(void);

/* Set ethernet header; returns the size of the header */
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,
                                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);
/* Set ports  */
void net_set_ports( int server_port, int our_port );
/* Sequence number and SAK management */
void net_tcp_hole_contract( u32 tcp_seq_num, u32 tcp_end_num );
void net_tcp_hole_expand( u32 tcp_seq_num, u32 tcp_end_num );

/* 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
 *
 * @addr:       Address to check (must be 16-bit aligned)
 * @nbytes:     Number of bytes to check (normally a multiple of 2)
 * @return 16-bit IP checksum
 */
unsigned compute_ip_checksum(const void *addr, unsigned nbytes);

/**
 * add_ip_checksums() - add two IP checksums
 *
 * @offset:     Offset of first sum (if odd we do a byte-swap)
 * @sum:        First checksum
 * @new_sum:    New checksum to add
 * @return updated 16-bit IP checksum
 */
unsigned add_ip_checksums(unsigned offset, unsigned sum, unsigned new_sum);

/**
 * ip_checksum_ok() - check if a checksum is correct
 *
 * This works by making sure the checksum sums to 0
 *
 * @addr:       Address to check (must be 16-bit aligned)
 * @nbytes:     Number of bytes to check (normally a multiple of 2)
 * @return true if the checksum matches, false if not
 */
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 */
void net_set_arp_handler(rxhand_f *);   /* Set ARP RX packet handler */
void net_set_icmp_handler(rxhand_icmp_f *f);    /* Set ICMP RX handlr*/
void net_set_timeout_handler(ulong, thand_f *); /* Set timeout handlr*/

/* Network loop state */
enum net_loop_state {
        NETLOOP_CONTINUE,
        NETLOOP_RESTART,
        NETLOOP_SUCCESS,
        NETLOOP_FAIL
};
extern enum net_loop_state net_state;

static inline void net_set_state(enum net_loop_state state)
{
        debug_cond(DEBUG_INT_STATE, "--- NetState set to %d\n", state);
        net_state = state;
}

/* Transmit a packet */
static inline void net_send_packet(uchar *pkt, int len)
{
        /* Currently no way to return errors from eth_send() */
        (void) eth_send(pkt, len);
}

/*
 * Transmit "net_tx_packet" as UDP packet, performing ARP request if needed
 *  (ether will be populated)
 *
 * @param ether Raw packet buffer
 * @param dest IP address to send the datagram to
 * @param dport Destination UDP port
 * @param sport Source UDP port
 * @param payload_len Length of data after the UDP header
 * Added TCP support and protocol parameter for sending ip packets, and
 * shim to support existing udp interface.
 */

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);

/* Processes a received packet */
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);
#endif

static __always_inline int eth_is_on_demand_init(void)
{
#ifdef CONFIG_NETCONSOLE
        extern enum proto_t net_loop_last_protocol;

        return net_loop_last_protocol != NETCONS;
#else
        return 1;
#endif
}

static inline void eth_set_last_protocol(int protocol)
{
#ifdef CONFIG_NETCONSOLE
        extern enum proto_t net_loop_last_protocol;

        net_loop_last_protocol = protocol;
#endif
}

/*
 * Check if autoload is enabled. If so, use either NFS or TFTP to download
 * the boot file.
 */
void net_auto_load(void);

/*
 * The following functions are a bit ugly, but necessary to deal with
 * alignment restrictions on ARM.
 *
 * We're using inline functions, which had the smallest memory
 * footprint in our tests.
 */
/* return IP *in network byteorder* */
static inline struct in_addr net_read_ip(void *from)
{
        struct in_addr ip;

        memcpy((void *)&ip, (void *)from, sizeof(ip));
        return ip;
}

/* return ulong *in network byteorder* */
static inline u32 net_read_u32(u32 *from)
{
        u32 l;

        memcpy((void *)&l, (void *)from, sizeof(l));
        return l;
}

/* write IP *in network byteorder* */
static inline void net_write_ip(void *to, struct in_addr ip)
{
        memcpy(to, (void *)&ip, sizeof(ip));
}

/* copy IP */
static inline void net_copy_ip(void *to, void *from)
{
        memcpy((void *)to, from, sizeof(struct in_addr));
}

/* copy ulong */
static inline void net_copy_u32(u32 *to, u32 *from)
{
        memcpy((void *)to, (void *)from, sizeof(u32));
}

/**
 * is_zero_ethaddr - Determine if give Ethernet address is all zeros.
 * @addr: Pointer to a six-byte array containing the Ethernet address
 *
 * Return true if the address is all zeroes.
 */
static inline int is_zero_ethaddr(const u8 *addr)
{
        return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]);
}

/**
 * is_multicast_ethaddr - Determine if the Ethernet address is a multicast.
 * @addr: Pointer to a six-byte array containing the Ethernet address
 *
 * Return true if the address is a multicast address.
 * By definition the broadcast address is also a multicast address.
 */
static inline int is_multicast_ethaddr(const u8 *addr)
{
        return 0x01 & addr[0];
}

/*
 * is_broadcast_ethaddr - Determine if the Ethernet address is broadcast
 * @addr: Pointer to a six-byte array containing the Ethernet address
 *
 * Return true if the address is the broadcast address.
 */
static inline int is_broadcast_ethaddr(const u8 *addr)
{
        return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) ==
                0xff;
}

/*
 * is_valid_ethaddr - Determine if the given Ethernet address is valid
 * @addr: Pointer to a six-byte array containing the Ethernet address
 *
 * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not
 * a multicast address, and is not FF:FF:FF:FF:FF:FF.
 *
 * Return true if the address is valid.
 */
static inline int is_valid_ethaddr(const u8 *addr)
{
        /* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to
         * explicitly check for it here. */
        return !is_multicast_ethaddr(addr) && !is_zero_ethaddr(addr);
}

/**
 * net_random_ethaddr - Generate software assigned random Ethernet address
 * @addr: Pointer to a six-byte array containing the Ethernet address
 *
 * Generate a random Ethernet address (MAC) that is not multicast
 * and has the local assigned bit set.
 */
static inline void net_random_ethaddr(uchar *addr)
{
        int i;
        unsigned int seed = get_timer(0);

        for (i = 0; i < 6; i++)
                addr[i] = rand_r(&seed);

        addr[0] &= 0xfe;        /* clear multicast bit */
        addr[0] |= 0x02;        /* set local assignment bit (IEEE802) */
}

/* Convert an IP address to a string */
void ip_to_string(struct in_addr x, char *s);

/* Convert a string to ip address */
struct in_addr string_to_ip(const char *s);

/* Convert a VLAN id to a string */
void vlan_to_string(ushort x, char *s);

/* Convert a string to a vlan id */
ushort string_to_vlan(const char *s);

/* read a VLAN id from an environment variable */
ushort getenv_vlan(char *);

/* copy a filename (allow for "..." notation, limit length) */
void copy_filename(char *dst, const char *src, int size);

/* get a random source port */
unsigned int random_port(void);

/**
 * update_tftp - Update firmware over TFTP (via DFU)
 *
 * This function updates board's firmware via TFTP
 *
 * @param addr - memory address where data is stored
 * @param interface - the DFU medium name - e.g. "mmc"
 * @param devstring - the DFU medium number - e.g. "1"
 *
 * @return - 0 on success, other value on failure
 */
int update_tftp(ulong addr, char *interface, char *devstring);

/**********************************************************************/

#endif /* __NET_H__ */

net/wget.c



        
        
        
        


/*
 * FILE  support driver - based on etherboot and U-BOOT's tftp.c
 *
 * Duncan Hare <d...@synoia.com> 2017
 *
 */


#include <common.h>
#include <command.h>
#include <fat.h>        //FAT
#include <net.h>
#include <mapmem.h>

#ifdef TCP

#define         FILE_TEST 0     /* Set to 1 for debug messges */

#define         FILE_RETRY_COUNT 30
#ifndef         CONFIG_FILE_TIMEOUT
# define        FILE_TIMEOUT    2000UL
#define         SERVER_PORT     8081
#else
# define        FILE_TIMEOUT CONFIG_FILE_TIMEOUT
#endif

char bootfile[50]       = "GET /r.32.test/boot/cmdline.txt HTTP/1.1\r\n\r\n";
char bootfile1[10]      = "GET ";
char bootfile2[30]      = "/r.32.test/boot/cmdline.txt";
char bootfile3[20]      = " HTTP/1.1\r\n\r\n";

uchar content[6]        = "<html>";
uchar error404[3]       = "404";

static unsigned int file_timeout = FILE_TIMEOUT;

static struct   in_addr file_server_ip;
static int      file_timeout_count;
int packets = 0;

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];
int i  = 0;

static void file_timeout_handler(void);
void file_fail( char * error_message, unsigned tcp_seq_num, unsigned 
tcp_ack_num, u8 action );

static inline int store_block(uchar *src, unsigned offset, unsigned 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);
                if ( i < 3 )
                {
                        printf( "Offset %d, Length %d\n", offset, len );
                        net_print_buffer( src, 24, 24, 24, 0 );
                        i++;
                        net_print_buffer( src + len -24, (int)src + len -24, 
24, 24, 0);
                }
                unmap_sysmem(ptr);
        }

        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 tcp_ack_num, unsigned 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 );
                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, &bootfile2, strlen(bootfile2) );
//                      offset = offset + strlen(bootfile2);

                        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 tcp_seq_num, unsigned 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 tcp_seq_num, unsigned 
tcp_ack_num, u8 action )
{
        debug_cond( FILE_TEST, error_message );
        debug_cond( FILE_TEST, "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 $
         * packet pointer, and the other variable "repurposed" (or misused) to 
carry sequen$
         * and  TCP state.
         *
         * Parms: ((uchar *) b, tcp_ack_num, action_and_state, tcp_seq_num, 
payload_len );
         *
        */


static void file_handler(uchar *pkt, unsigned tcp_seq_num, struct in_addr 
action_and_state,
                        unsigned tcp_ack_num, unsigned 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 Handler 
Connecting, 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 Connected 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 );
                                pkt[0] = 0x00;
                                file_fail( (char *)pkt, tcp_seq_num, 
tcp_ack_num, action );
                        }
                        else                                            /* Got 
HTTP Header      */
                        {
                                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 )
                        {
                                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;
                                }
                        }
                        else file_send( action , tcp_seq_num, tcp_ack_num, len 
);
                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 == NULL) {
                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 != NULL) {
                        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 via HTTP from server %pI4; our IP 
address is %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 );
}
#endif
wget.h
/*
 * Duncan Hare Copyright 2017
*/

void wget_start(void);   /* Begin NFS */
net/ping.c changes
        struct icmp_hdr *icmp = (struct icmp_hdr *)(pkt + 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;
        icmp->checksum = 0;
        icmp->un.echo.id = 0;
        icmp->un.echo.sequence = htons(ping_seq_number++);
        icmp->checksum = compute_ip_checksum(icmp, ICMP_HDR_SIZE);
n Hare

714 931 7952
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to