[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit

Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/boot/common/src/uboot/net/Makefile b/boot/common/src/uboot/net/Makefile
new file mode 100644
index 0000000..417f175
--- /dev/null
+++ b/boot/common/src/uboot/net/Makefile
@@ -0,0 +1,59 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+# CFLAGS += -DDEBUG
+
+LIB	= $(obj)libnet.o
+
+COBJS-$(CONFIG_CMD_NET)  += arp.o
+COBJS-$(CONFIG_CMD_NET)  += bootp.o
+COBJS-$(CONFIG_CMD_CDP)  += cdp.o
+COBJS-$(CONFIG_CMD_DNS)  += dns.o
+COBJS-$(CONFIG_CMD_NET)  += eth.o
+COBJS-$(CONFIG_CMD_LINK_LOCAL) += link_local.o
+COBJS-$(CONFIG_CMD_NET)  += net.o
+COBJS-$(CONFIG_CMD_NFS)  += nfs.o
+COBJS-$(CONFIG_CMD_PING) += ping.o
+COBJS-$(CONFIG_CMD_RARP) += rarp.o
+COBJS-$(CONFIG_CMD_SNTP) += sntp.o
+COBJS-$(CONFIG_CMD_NET)  += tftp.o
+
+COBJS	:= $(COBJS-y)
+SRCS	:= $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+
+all:	$(LIB)
+
+$(LIB):	$(obj).depend $(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/boot/common/src/uboot/net/arp.c b/boot/common/src/uboot/net/arp.c
new file mode 100644
index 0000000..8d6f99b
--- /dev/null
+++ b/boot/common/src/uboot/net/arp.c
@@ -0,0 +1,248 @@
+/*
+ *	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, wd@denx.de
+ */
+
+#include <common.h>
+
+#include "arp.h"
+extern uint32_t g_gmac_init_overtime;
+extern ulong  time_over;
+#ifndef	CONFIG_ARP_TIMEOUT
+/* Milliseconds before trying ARP again */
+
+# define ARP_TIMEOUT	5000UL
+
+//uint32_t  ARP_TIMEOUT = g_gmac_init_overtime*5000/3UL;
+
+#else
+# define ARP_TIMEOUT		CONFIG_ARP_TIMEOUT
+#endif
+
+
+#ifndef	CONFIG_NET_RETRY_COUNT
+# define ARP_TIMEOUT_COUNT	5	/* # of timeouts before giving up  */
+#else
+# define ARP_TIMEOUT_COUNT	CONFIG_NET_RETRY_COUNT
+#endif
+
+IPaddr_t	NetArpWaitPacketIP;
+static IPaddr_t	NetArpWaitReplyIP;
+/* MAC address of waiting packet's destination */
+uchar	       *NetArpWaitPacketMAC;
+int		NetArpWaitTxPacketSize;
+ulong		NetArpWaitTimerStart;
+int		NetArpWaitTry;
+
+static uchar   *NetArpTxPacket;	/* THE ARP transmit packet */
+static uchar	NetArpPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
+int arp_cnt;
+
+void ArpInit(void)
+{
+	/* XXX problem with bss workaround */
+	NetArpWaitPacketMAC = NULL;
+	NetArpWaitPacketIP = 0;
+	NetArpWaitReplyIP = 0;
+	NetArpWaitTxPacketSize = 0;
+	NetArpTxPacket = &NetArpPacketBuf[0] + (PKTALIGN - 1);
+	NetArpTxPacket -= (ulong)NetArpTxPacket % PKTALIGN;
+}
+
+void arp_raw_request(IPaddr_t sourceIP, const uchar *targetEther,
+	IPaddr_t targetIP)
+{
+	uchar *pkt;
+	struct arp_hdr *arp;
+	int eth_hdr_size;
+
+	//debug_cond(DEBUG_DEV_PKT, "ARP broadcast %d\n", NetArpWaitTry);
+	printf("ARP broadcast %d\n", NetArpWaitTry);
+		++arp_cnt;
+
+	pkt = NetArpTxPacket;
+
+	eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_ARP);
+	pkt += eth_hdr_size;
+
+	arp = (struct arp_hdr *) pkt;
+
+	arp->ar_hrd = htons(ARP_ETHER);
+	arp->ar_pro = htons(PROT_IP);
+	arp->ar_hln = ARP_HLEN;
+	arp->ar_pln = ARP_PLEN;
+	arp->ar_op = htons(ARPOP_REQUEST);
+
+	memcpy(&arp->ar_sha, NetOurEther, ARP_HLEN);	/* source ET addr */
+	NetWriteIP(&arp->ar_spa, sourceIP);		/* source IP addr */
+	memcpy(&arp->ar_tha, targetEther, ARP_HLEN);	/* target ET addr */
+	NetWriteIP(&arp->ar_tpa, targetIP);		/* target IP addr */
+
+	NetSendPacket(NetArpTxPacket, eth_hdr_size + ARP_HDR_SIZE);
+}
+
+void ArpRequest(void)
+{
+	if ((NetArpWaitPacketIP & NetOurSubnetMask) !=
+	    (NetOurIP & NetOurSubnetMask)) {
+		if (NetOurGatewayIP == 0) {
+			puts("## Warning: gatewayip needed but not set\n");
+			NetArpWaitReplyIP = NetArpWaitPacketIP;
+		} else {
+			NetArpWaitReplyIP = NetOurGatewayIP;
+		}
+	} else {
+		NetArpWaitReplyIP = NetArpWaitPacketIP;
+	}
+
+	arp_raw_request(NetOurIP, NetEtherNullAddr, NetArpWaitReplyIP);
+}
+
+void ArpTimeoutCheck(void)
+{
+	ulong t;
+
+	if (!NetArpWaitPacketIP)
+		return;
+
+	t = get_timer(0);
+
+	/* check for arp timeout */
+	if ((t - NetArpWaitTimerStart) >  time_over) {
+		//++arp_cnt;
+		NetArpWaitTry++;
+
+		if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
+			puts("\nARP Retry count exceeded; starting again\n");
+			NetArpWaitTry = 0;
+			NetStartAgain();
+		} else {
+			NetArpWaitTimerStart = t;
+			ArpRequest();
+			
+		}
+	}
+}
+
+void ArpReceive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len)
+{
+	struct arp_hdr *arp;
+	IPaddr_t reply_ip_addr;
+	uchar *pkt;
+	int eth_hdr_size;
+
+	/*
+	 * We have to deal with two types of ARP packets:
+	 * - REQUEST packets will be answered by sending  our
+	 *   IP address - if we know it.
+	 * - REPLY packates are expected only after we asked
+	 *   for the TFTP server's or the gateway's ethernet
+	 *   address; so if we receive such a packet, we set
+	 *   the server ethernet address
+	 */
+	debug_cond(DEBUG_NET_PKT, "Got ARP\n");
+
+	arp = (struct arp_hdr *)ip;
+	if (len < ARP_HDR_SIZE) {
+		printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
+		return;
+	}
+	if (ntohs(arp->ar_hrd) != ARP_ETHER)
+		return;
+	if (ntohs(arp->ar_pro) != PROT_IP)
+		return;
+	if (arp->ar_hln != ARP_HLEN)
+		return;
+	if (arp->ar_pln != ARP_PLEN)
+		return;
+
+	if (NetOurIP == 0)
+		return;
+
+	if (NetReadIP(&arp->ar_tpa) != NetOurIP)
+		return;
+
+	switch (ntohs(arp->ar_op)) {
+	case ARPOP_REQUEST:
+		/* reply with our IP address */
+		//debug_cond(DEBUG_DEV_PKT, "Got ARP REQUEST, return our IP\n");
+		printf("Got ARP REQUEST, return our IP\n");
+		pkt = (uchar *)et;
+		eth_hdr_size = net_update_ether(et, et->et_src, PROT_ARP);
+		pkt += eth_hdr_size;
+		arp->ar_op = htons(ARPOP_REPLY);
+		memcpy(&arp->ar_tha, &arp->ar_sha, ARP_HLEN);
+		NetCopyIP(&arp->ar_tpa, &arp->ar_spa);
+		memcpy(&arp->ar_sha, NetOurEther, ARP_HLEN);
+		NetCopyIP(&arp->ar_spa, &NetOurIP);
+
+#ifdef CONFIG_CMD_LINK_LOCAL
+		/*
+		 * Work-around for brain-damaged Cisco equipment with
+		 *   arp-proxy enabled.
+		 *
+		 *   If the requesting IP is not on our subnet, wait 5ms to
+		 *   reply to ARP request so that our reply will overwrite
+		 *   the arp-proxy's instead of the other way around.
+		 */
+		if ((NetReadIP(&arp->ar_tpa) & NetOurSubnetMask) !=
+		    (NetReadIP(&arp->ar_spa) & NetOurSubnetMask))
+			udelay(5000);
+#endif
+		NetSendPacket((uchar *)et, eth_hdr_size + ARP_HDR_SIZE);
+		return;
+
+	case ARPOP_REPLY:		/* arp reply */
+		/* are we waiting for a reply */
+		if (!NetArpWaitPacketIP)
+			break;
+
+#ifdef CONFIG_KEEP_SERVERADDR
+		if (NetServerIP == NetArpWaitPacketIP) {
+			char buf[20];
+			sprintf(buf, "%pM", &arp->ar_sha);
+			setenv("serveraddr", buf);
+		}
+#endif
+
+		reply_ip_addr = NetReadIP(&arp->ar_spa);
+
+		/* matched waiting packet's address */
+		if (reply_ip_addr == NetArpWaitReplyIP) 
+		{
+			//debug_cond(DEBUG_DEV_PKT,
+			//	"Got ARP REPLY, set eth addr (%pM)\n",
+			//	arp->ar_data);
+			printf("Got ARP REPLY, set eth addr (%pM)\n",arp->ar_data);
+			/* save address for later use */
+			if (NetArpWaitPacketMAC != NULL)
+				memcpy(NetArpWaitPacketMAC,
+				       &arp->ar_sha, ARP_HLEN);
+
+			net_get_arp_handler()((uchar *)arp, 0, reply_ip_addr, 0, len);//???????
+
+			/* set the mac address in the waiting packet's header
+			   and transmit it */
+			memcpy(((struct ethernet_hdr *)NetTxPacket)->et_dest,
+				&arp->ar_sha, ARP_HLEN);
+			NetSendPacket(NetTxPacket, NetArpWaitTxPacketSize);
+
+			/* no arp request pending now */
+			NetArpWaitPacketIP = 0;
+			NetArpWaitTxPacketSize = 0;
+			NetArpWaitPacketMAC = NULL;
+
+		}
+		return;
+	default:
+		//debug("Unexpected ARP opcode 0x%x\n",
+		      //ntohs(arp->ar_op));
+		printf("Unexpected ARP opcode 0x%x\n",ntohs(arp->ar_op));
+		return;
+	}
+}
diff --git a/boot/common/src/uboot/net/arp.h b/boot/common/src/uboot/net/arp.h
new file mode 100644
index 0000000..bfd57e0
--- /dev/null
+++ b/boot/common/src/uboot/net/arp.h
@@ -0,0 +1,30 @@
+/*
+ *	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, wd@denx.de
+ */
+
+#ifndef __ARP_H__
+#define __ARP_H__
+
+#include <common.h>
+
+extern IPaddr_t	NetArpWaitPacketIP;
+/* MAC address of waiting packet's destination */
+extern uchar *NetArpWaitPacketMAC;
+extern int NetArpWaitTxPacketSize;
+extern ulong NetArpWaitTimerStart;
+extern int NetArpWaitTry;
+
+void ArpInit(void);
+void ArpRequest(void);
+void arp_raw_request(IPaddr_t sourceIP, const uchar *targetEther,
+	IPaddr_t targetIP);
+void ArpTimeoutCheck(void);
+void ArpReceive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len);
+
+#endif /* __ARP_H__ */
diff --git a/boot/common/src/uboot/net/bootp.c b/boot/common/src/uboot/net/bootp.c
new file mode 100644
index 0000000..9723578
--- /dev/null
+++ b/boot/common/src/uboot/net/bootp.c
@@ -0,0 +1,963 @@
+/*
+ *	Based on LiMon - BOOTP.
+ *
+ *	Copyright 1994, 1995, 2000 Neil Russell.
+ *	(See License)
+ *	Copyright 2000 Roland Borde
+ *	Copyright 2000 Paolo Scaffardi
+ *	Copyright 2000-2004 Wolfgang Denk, wd@denx.de
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include "bootp.h"
+#include "tftp.h"
+#include "nfs.h"
+#ifdef CONFIG_STATUS_LED
+#include <status_led.h>
+#endif
+#ifdef CONFIG_BOOTP_RANDOM_DELAY
+#include "net_rand.h"
+#endif
+
+#define BOOTP_VENDOR_MAGIC	0x63825363	/* RFC1048 Magic Cookie */
+
+#define TIMEOUT		5000UL	/* Milliseconds before trying BOOTP again */
+#ifndef CONFIG_NET_RETRY_COUNT
+# define TIMEOUT_COUNT	5		/* # of timeouts before giving up */
+#else
+# define TIMEOUT_COUNT	(CONFIG_NET_RETRY_COUNT)
+#endif
+
+#define PORT_BOOTPS	67		/* BOOTP server UDP port */
+#define PORT_BOOTPC	68		/* BOOTP client UDP port */
+
+#ifndef CONFIG_DHCP_MIN_EXT_LEN		/* minimal length of extension list */
+#define CONFIG_DHCP_MIN_EXT_LEN 64
+#endif
+
+ulong		BootpID;
+int		BootpTry;
+
+#if defined(CONFIG_CMD_DHCP)
+static dhcp_state_t dhcp_state = INIT;
+static unsigned long dhcp_leasetime;
+static IPaddr_t NetDHCPServerIP;
+static void DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+			unsigned len);
+
+/* For Debug */
+#if 0
+static char *dhcpmsg2str(int type)
+{
+	switch (type) {
+	case 1:	 return "DHCPDISCOVER"; break;
+	case 2:	 return "DHCPOFFER";	break;
+	case 3:	 return "DHCPREQUEST";	break;
+	case 4:	 return "DHCPDECLINE";	break;
+	case 5:	 return "DHCPACK";	break;
+	case 6:	 return "DHCPNACK";	break;
+	case 7:	 return "DHCPRELEASE";	break;
+	default: return "UNKNOWN/INVALID MSG TYPE"; break;
+	}
+}
+#endif
+#endif
+
+static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len)
+{
+	struct Bootp_t *bp = (struct Bootp_t *) pkt;
+	int retval = 0;
+
+	if (dest != PORT_BOOTPC || src != PORT_BOOTPS)
+		retval = -1;
+	else if (len < sizeof(struct Bootp_t) - OPT_FIELD_SIZE)
+		retval = -2;
+	else if (bp->bp_op != OP_BOOTREQUEST &&
+			bp->bp_op != OP_BOOTREPLY &&
+			bp->bp_op != DHCP_OFFER &&
+			bp->bp_op != DHCP_ACK &&
+			bp->bp_op != DHCP_NAK)
+		retval = -3;
+	else if (bp->bp_htype != HWT_ETHER)
+		retval = -4;
+	else if (bp->bp_hlen != HWL_ETHER)
+		retval = -5;
+	else if (NetReadLong((ulong *)&bp->bp_id) != BootpID)
+		retval = -6;
+
+	debug("Filtering pkt = %d\n", retval);
+
+	return retval;
+}
+
+/*
+ * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet
+ */
+static void BootpCopyNetParams(struct Bootp_t *bp)
+{
+#if !defined(CONFIG_BOOTP_SERVERIP)
+	IPaddr_t tmp_ip;
+
+	NetCopyIP(&tmp_ip, &bp->bp_siaddr);
+	if (tmp_ip != 0)
+		NetCopyIP(&NetServerIP, &bp->bp_siaddr);
+	memcpy(NetServerEther, ((struct ethernet_hdr *)NetRxPacket)->et_src, 6);
+#endif
+	NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
+	if (strlen(bp->bp_file) > 0)
+		copy_filename(BootFile, bp->bp_file, sizeof(BootFile));
+
+	debug("Bootfile: %s\n", BootFile);
+
+	/* Propagate to environment:
+	 * don't delete exising entry when BOOTP / DHCP reply does
+	 * not contain a new value
+	 */
+	if (*BootFile)
+		setenv("bootfile", BootFile);
+}
+
+static int truncate_sz(const char *name, int maxlen, int curlen)
+{
+	if (curlen >= maxlen) {
+		printf("*** WARNING: %s is too long (%d - max: %d)"
+			" - truncated\n", name, curlen, maxlen);
+		curlen = maxlen - 1;
+	}
+	return curlen;
+}
+
+#if !defined(CONFIG_CMD_DHCP)
+
+static void BootpVendorFieldProcess(u8 *ext)
+{
+	int size = *(ext + 1);
+
+	debug("[BOOTP] Processing extension %d... (%d bytes)\n", *ext,
+		*(ext + 1));
+
+	NetBootFileSize = 0;
+
+	switch (*ext) {
+		/* Fixed length fields */
+	case 1:			/* Subnet mask */
+		if (NetOurSubnetMask == 0)
+			NetCopyIP(&NetOurSubnetMask, (IPaddr_t *) (ext + 2));
+		break;
+	case 2:			/* Time offset - Not yet supported */
+		break;
+		/* Variable length fields */
+	case 3:			/* Gateways list */
+		if (NetOurGatewayIP == 0)
+			NetCopyIP(&NetOurGatewayIP, (IPaddr_t *) (ext + 2));
+		break;
+	case 4:			/* Time server - Not yet supported */
+		break;
+	case 5:			/* IEN-116 name server - Not yet supported */
+		break;
+	case 6:
+		if (NetOurDNSIP == 0)
+			NetCopyIP(&NetOurDNSIP, (IPaddr_t *) (ext + 2));
+#if defined(CONFIG_BOOTP_DNS2)
+		if ((NetOurDNS2IP == 0) && (size > 4))
+			NetCopyIP(&NetOurDNS2IP, (IPaddr_t *) (ext + 2 + 4));
+#endif
+		break;
+	case 7:			/* Log server - Not yet supported */
+		break;
+	case 8:			/* Cookie/Quote server - Not yet supported */
+		break;
+	case 9:			/* LPR server - Not yet supported */
+		break;
+	case 10:		/* Impress server - Not yet supported */
+		break;
+	case 11:		/* RPL server - Not yet supported */
+		break;
+	case 12:		/* Host name */
+		if (NetOurHostName[0] == 0) {
+			size = truncate_sz("Host Name",
+				sizeof(NetOurHostName), size);
+			memcpy(&NetOurHostName, ext + 2, size);
+			NetOurHostName[size] = 0;
+		}
+		break;
+	case 13:		/* Boot file size */
+		if (size == 2)
+			NetBootFileSize = ntohs(*(ushort *) (ext + 2));
+		else if (size == 4)
+			NetBootFileSize = ntohl(*(ulong *) (ext + 2));
+		break;
+	case 14:		/* Merit dump file - Not yet supported */
+		break;
+	case 15:		/* Domain name - Not yet supported */
+		break;
+	case 16:		/* Swap server - Not yet supported */
+		break;
+	case 17:		/* Root path */
+		if (NetOurRootPath[0] == 0) {
+			size = truncate_sz("Root Path",
+				sizeof(NetOurRootPath), size);
+			memcpy(&NetOurRootPath, ext + 2, size);
+			NetOurRootPath[size] = 0;
+		}
+		break;
+	case 18:		/* Extension path - Not yet supported */
+		/*
+		 * This can be used to send the information of the
+		 * vendor area in another file that the client can
+		 * access via TFTP.
+		 */
+		break;
+		/* IP host layer fields */
+	case 40:		/* NIS Domain name */
+		if (NetOurNISDomain[0] == 0) {
+			size = truncate_sz("NIS Domain Name",
+				sizeof(NetOurNISDomain), size);
+			memcpy(&NetOurNISDomain, ext + 2, size);
+			NetOurNISDomain[size] = 0;
+		}
+		break;
+#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
+	case 42:	/* NTP server IP */
+		NetCopyIP(&NetNtpServerIP, (IPaddr_t *) (ext + 2));
+		break;
+#endif
+		/* Application layer fields */
+	case 43:		/* Vendor specific info - Not yet supported */
+		/*
+		 * Binary information to exchange specific
+		 * product information.
+		 */
+		break;
+		/* Reserved (custom) fields (128..254) */
+	}
+}
+
+static void BootpVendorProcess(u8 *ext, int size)
+{
+	u8 *end = ext + size;
+
+	debug("[BOOTP] Checking extension (%d bytes)...\n", size);
+
+	while ((ext < end) && (*ext != 0xff)) {
+		if (*ext == 0) {
+			ext++;
+		} else {
+			u8 *opt = ext;
+
+			ext += ext[1] + 2;
+			if (ext <= end)
+				BootpVendorFieldProcess(opt);
+		}
+	}
+
+	debug("[BOOTP] Received fields:\n");
+	if (NetOurSubnetMask)
+		debug("NetOurSubnetMask : %pI4\n", &NetOurSubnetMask);
+
+	if (NetOurGatewayIP)
+		debug("NetOurGatewayIP	: %pI4", &NetOurGatewayIP);
+
+	if (NetBootFileSize)
+		debug("NetBootFileSize : %d\n", NetBootFileSize);
+
+	if (NetOurHostName[0])
+		debug("NetOurHostName  : %s\n", NetOurHostName);
+
+	if (NetOurRootPath[0])
+		debug("NetOurRootPath  : %s\n", NetOurRootPath);
+
+	if (NetOurNISDomain[0])
+		debug("NetOurNISDomain : %s\n", NetOurNISDomain);
+
+	if (NetBootFileSize)
+		debug("NetBootFileSize: %d\n", NetBootFileSize);
+
+#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
+	if (NetNtpServerIP)
+		debug("NetNtpServerIP : %pI4\n", &NetNtpServerIP);
+#endif
+}
+
+/*
+ *	Handle a BOOTP received packet.
+ */
+static void
+BootpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+	     unsigned len)
+{
+	struct Bootp_t *bp;
+
+	debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n",
+		src, dest, len, sizeof(struct Bootp_t));
+
+	bp = (struct Bootp_t *)pkt;
+
+	/* Filter out pkts we don't want */
+	if (BootpCheckPkt(pkt, dest, src, len))
+		return;
+
+	/*
+	 *	Got a good BOOTP reply.	 Copy the data into our variables.
+	 */
+#ifdef CONFIG_STATUS_LED
+	status_led_set(STATUS_LED_BOOT, STATUS_LED_OFF);
+#endif
+
+	BootpCopyNetParams(bp);		/* Store net parameters from reply */
+
+	/* Retrieve extended information (we must parse the vendor area) */
+	if (NetReadLong((ulong *)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
+		BootpVendorProcess((uchar *)&bp->bp_vend[4], len);
+
+	NetSetTimeout(0, (thand_f *)0);
+	//bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop");
+
+	debug("Got good BOOTP\n");
+
+	net_auto_load();
+}
+#endif
+
+/*
+ *	Timeout on BOOTP/DHCP request.
+ */
+static void
+BootpTimeout(void)
+{
+	if (BootpTry >= TIMEOUT_COUNT) {
+#ifdef CONFIG_BOOTP_MAY_FAIL
+		puts("\nRetry count exceeded\n");
+		net_set_state(NETLOOP_FAIL);
+#else
+		puts("\nRetry count exceeded; starting again\n");
+		NetStartAgain();
+#endif
+	} else {
+		NetSetTimeout(TIMEOUT, BootpTimeout);
+		BootpRequest();
+	}
+}
+
+#define put_vci(e, str)						\
+	do {							\
+		size_t vci_strlen = strlen(str);		\
+		*e++ = 60;	/* Vendor Class Identifier */	\
+		*e++ = vci_strlen;				\
+		memcpy(e, str, vci_strlen);			\
+		e += vci_strlen;				\
+	} while (0)
+
+/*
+ *	Initialize BOOTP extension fields in the request.
+ */
+#if defined(CONFIG_CMD_DHCP)
+static int DhcpExtended(u8 *e, int message_type, IPaddr_t ServerID,
+			IPaddr_t RequestedIP)
+{
+	u8 *start = e;
+	u8 *cnt;
+#if defined(CONFIG_BOOTP_PXE)
+	char *uuid;
+	u16 clientarch;
+#endif
+
+#if defined(CONFIG_BOOTP_VENDOREX)
+	u8 *x;
+#endif
+#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
+	char *hostname;
+#endif
+
+	*e++ = 99;		/* RFC1048 Magic Cookie */
+	*e++ = 130;
+	*e++ = 83;
+	*e++ = 99;
+
+	*e++ = 53;		/* DHCP Message Type */
+	*e++ = 1;
+	*e++ = message_type;
+
+	*e++ = 57;		/* Maximum DHCP Message Size */
+	*e++ = 2;
+	*e++ = (576 - 312 + OPT_FIELD_SIZE) >> 8;
+	*e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
+
+	if (ServerID) {
+		int tmp = ntohl(ServerID);
+
+		*e++ = 54;	/* ServerID */
+		*e++ = 4;
+		*e++ = tmp >> 24;
+		*e++ = tmp >> 16;
+		*e++ = tmp >> 8;
+		*e++ = tmp & 0xff;
+	}
+
+	if (RequestedIP) {
+		int tmp = ntohl(RequestedIP);
+
+		*e++ = 50;	/* Requested IP */
+		*e++ = 4;
+		*e++ = tmp >> 24;
+		*e++ = tmp >> 16;
+		*e++ = tmp >> 8;
+		*e++ = tmp & 0xff;
+	}
+#if defined(CONFIG_BOOTP_SEND_HOSTNAME)
+	hostname = getenv("hostname");
+	if (hostname) {
+		int hostnamelen = strlen(hostname);
+
+		*e++ = 12;	/* Hostname */
+		*e++ = hostnamelen;
+		memcpy(e, hostname, hostnamelen);
+		e += hostnamelen;
+	}
+#endif
+
+#if defined(CONFIG_BOOTP_PXE)
+	clientarch = CONFIG_BOOTP_PXE_CLIENTARCH;
+	*e++ = 93;	/* Client System Architecture */
+	*e++ = 2;
+	*e++ = (clientarch >> 8) & 0xff;
+	*e++ = clientarch & 0xff;
+
+	*e++ = 94;	/* Client Network Interface Identifier */
+	*e++ = 3;
+	*e++ = 1;	/* type field for UNDI */
+	*e++ = 0;	/* major revision */
+	*e++ = 0;	/* minor revision */
+
+	uuid = getenv("pxeuuid");
+
+	if (uuid) {
+		if (uuid_str_valid(uuid)) {
+			*e++ = 97;	/* Client Machine Identifier */
+			*e++ = 17;
+			*e++ = 0;	/* type 0 - UUID */
+
+			uuid_str_to_bin(uuid, e);
+			e += 16;
+		} else {
+			printf("Invalid pxeuuid: %s\n", uuid);
+		}
+	}
+#endif
+
+#ifdef CONFIG_BOOTP_VCI_STRING
+	put_vci(e, CONFIG_BOOTP_VCI_STRING);
+#endif
+
+#if defined(CONFIG_BOOTP_VENDOREX)
+	x = dhcp_vendorex_prep(e);
+	if (x)
+		return x - start;
+#endif
+
+	*e++ = 55;		/* Parameter Request List */
+	 cnt = e++;		/* Pointer to count of requested items */
+	*cnt = 0;
+#if defined(CONFIG_BOOTP_SUBNETMASK)
+	*e++  = 1;		/* Subnet Mask */
+	*cnt += 1;
+#endif
+#if defined(CONFIG_BOOTP_TIMEOFFSET)
+	*e++  = 2;
+	*cnt += 1;
+#endif
+#if defined(CONFIG_BOOTP_GATEWAY)
+	*e++  = 3;		/* Router Option */
+	*cnt += 1;
+#endif
+#if defined(CONFIG_BOOTP_DNS)
+	*e++  = 6;		/* DNS Server(s) */
+	*cnt += 1;
+#endif
+#if defined(CONFIG_BOOTP_HOSTNAME)
+	*e++  = 12;		/* Hostname */
+	*cnt += 1;
+#endif
+#if defined(CONFIG_BOOTP_BOOTFILESIZE)
+	*e++  = 13;		/* Boot File Size */
+	*cnt += 1;
+#endif
+#if defined(CONFIG_BOOTP_BOOTPATH)
+	*e++  = 17;		/* Boot path */
+	*cnt += 1;
+#endif
+#if defined(CONFIG_BOOTP_NISDOMAIN)
+	*e++  = 40;		/* NIS Domain name request */
+	*cnt += 1;
+#endif
+#if defined(CONFIG_BOOTP_NTPSERVER)
+	*e++  = 42;
+	*cnt += 1;
+#endif
+	/* no options, so back up to avoid sending an empty request list */
+	if (*cnt == 0)
+		e -= 2;
+
+	*e++  = 255;		/* End of the list */
+
+	/* Pad to minimal length */
+#ifdef	CONFIG_DHCP_MIN_EXT_LEN
+	while ((e - start) < CONFIG_DHCP_MIN_EXT_LEN)
+		*e++ = 0;
+#endif
+
+	return e - start;
+}
+
+#else
+/*
+ * Warning: no field size check - change CONFIG_BOOTP_* at your own risk!
+ */
+static int BootpExtended(u8 *e)
+{
+	u8 *start = e;
+
+	*e++ = 99;		/* RFC1048 Magic Cookie */
+	*e++ = 130;
+	*e++ = 83;
+	*e++ = 99;
+
+#if defined(CONFIG_CMD_DHCP)
+	*e++ = 53;		/* DHCP Message Type */
+	*e++ = 1;
+	*e++ = DHCP_DISCOVER;
+
+	*e++ = 57;		/* Maximum DHCP Message Size */
+	*e++ = 2;
+	*e++ = (576 - 312 + OPT_FIELD_SIZE) >> 16;
+	*e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff;
+#endif
+
+#if defined(CONFIG_BOOTP_VCI_STRING) || \
+	(defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING))
+#ifdef CONFIG_SPL_BUILD
+	put_vci(e, CONFIG_SPL_NET_VCI_STRING);
+#else
+	put_vci(e, CONFIG_BOOTP_VCI_STRING);
+#endif
+#endif
+
+#if defined(CONFIG_BOOTP_SUBNETMASK)
+	*e++ = 1;		/* Subnet mask request */
+	*e++ = 4;
+	e   += 4;
+#endif
+
+#if defined(CONFIG_BOOTP_GATEWAY)
+	*e++ = 3;		/* Default gateway request */
+	*e++ = 4;
+	e   += 4;
+#endif
+
+#if defined(CONFIG_BOOTP_DNS)
+	*e++ = 6;		/* Domain Name Server */
+	*e++ = 4;
+	e   += 4;
+#endif
+
+#if defined(CONFIG_BOOTP_HOSTNAME)
+	*e++ = 12;		/* Host name request */
+	*e++ = 32;
+	e   += 32;
+#endif
+
+#if defined(CONFIG_BOOTP_BOOTFILESIZE)
+	*e++ = 13;		/* Boot file size */
+	*e++ = 2;
+	e   += 2;
+#endif
+
+#if defined(CONFIG_BOOTP_BOOTPATH)
+	*e++ = 17;		/* Boot path */
+	*e++ = 32;
+	e   += 32;
+#endif
+
+#if defined(CONFIG_BOOTP_NISDOMAIN)
+	*e++ = 40;		/* NIS Domain name request */
+	*e++ = 32;
+	e   += 32;
+#endif
+#if defined(CONFIG_BOOTP_NTPSERVER)
+	*e++ = 42;
+	*e++ = 4;
+	e   += 4;
+#endif
+
+	*e++ = 255;		/* End of the list */
+
+	return e - start;
+}
+#endif
+
+void
+BootpRequest(void)
+{
+	uchar *pkt, *iphdr;
+	struct Bootp_t *bp;
+	int extlen, pktlen, iplen;
+	int eth_hdr_size;
+#ifdef CONFIG_BOOTP_RANDOM_DELAY
+	ulong i, rand_ms;
+#endif
+
+//	bootstage_mark_name(BOOTSTAGE_ID_BOOTP_START, "bootp_start");
+#if defined(CONFIG_CMD_DHCP)
+	dhcp_state = INIT;
+#endif
+
+#ifdef CONFIG_BOOTP_RANDOM_DELAY		/* Random BOOTP delay */
+	if (BootpTry == 0)
+		srand_mac();
+
+	if (BootpTry <= 2)	/* Start with max 1024 * 1ms */
+		rand_ms = rand() >> (22 - BootpTry);
+	else		/* After 3rd BOOTP request max 8192 * 1ms */
+		rand_ms = rand() >> 19;
+
+	printf("Random delay: %ld ms...\n", rand_ms);
+	for (i = 0; i < rand_ms; i++)
+		udelay(1000); /*Wait 1ms*/
+
+#endif	/* CONFIG_BOOTP_RANDOM_DELAY */
+
+	printf("BOOTP broadcast %d\n", ++BootpTry);
+	pkt = NetTxPacket;
+	memset((void *)pkt, 0, PKTSIZE);
+
+	eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_IP);
+	pkt += eth_hdr_size;
+
+	/*
+	 * Next line results in incorrect packet size being transmitted,
+	 * resulting in errors in some DHCP servers, reporting missing bytes.
+	 * Size must be set in packet header after extension length has been
+	 * determined.
+	 * C. Hallinan, DS4.COM, Inc.
+	 */
+	/* net_set_udp_header(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC,
+		sizeof (struct Bootp_t)); */
+	iphdr = pkt;	/* We need this later for net_set_udp_header() */
+	pkt += IP_UDP_HDR_SIZE;
+
+	bp = (struct Bootp_t *)pkt;
+	bp->bp_op = OP_BOOTREQUEST;
+	bp->bp_htype = HWT_ETHER;
+	bp->bp_hlen = HWL_ETHER;
+	bp->bp_hops = 0;
+	bp->bp_secs = htons(get_timer(0) / 1000);
+	NetWriteIP(&bp->bp_ciaddr, 0);
+	NetWriteIP(&bp->bp_yiaddr, 0);
+	NetWriteIP(&bp->bp_siaddr, 0);
+	NetWriteIP(&bp->bp_giaddr, 0);
+	memcpy(bp->bp_chaddr, NetOurEther, 6);
+	copy_filename(bp->bp_file, BootFile, sizeof(bp->bp_file));
+
+	/* Request additional information from the BOOTP/DHCP server */
+#if defined(CONFIG_CMD_DHCP)
+	extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0);
+#else
+	extlen = BootpExtended((u8 *)bp->bp_vend);
+#endif
+
+	/*
+	 *	Bootp ID is the lower 4 bytes of our ethernet address
+	 *	plus the current time in ms.
+	 */
+	BootpID = ((ulong)NetOurEther[2] << 24)
+		| ((ulong)NetOurEther[3] << 16)
+		| ((ulong)NetOurEther[4] << 8)
+		| (ulong)NetOurEther[5];
+	BootpID += get_timer(0);
+	BootpID	 = htonl(BootpID);
+	NetCopyLong(&bp->bp_id, &BootpID);
+
+	/*
+	 * Calculate proper packet lengths taking into account the
+	 * variable size of the options field
+	 */
+	iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
+	pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
+	net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
+	NetSetTimeout(SELECT_TIMEOUT, BootpTimeout);
+
+#if defined(CONFIG_CMD_DHCP)
+	dhcp_state = SELECTING;
+	net_set_udp_handler(DhcpHandler);
+#else
+	net_set_udp_handler(BootpHandler);
+#endif
+	NetSendPacket(NetTxPacket, pktlen);
+}
+
+#if defined(CONFIG_CMD_DHCP)
+static void DhcpOptionsProcess(uchar *popt, struct Bootp_t *bp)
+{
+	uchar *end = popt + BOOTP_HDR_SIZE;
+	int oplen, size;
+#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
+	int *to_ptr;
+#endif
+
+	while (popt < end && *popt != 0xff) {
+		oplen = *(popt + 1);
+		switch (*popt) {
+		case 1:
+			NetCopyIP(&NetOurSubnetMask, (popt + 2));
+			break;
+#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
+		case 2:		/* Time offset	*/
+			to_ptr = &NetTimeOffset;
+			NetCopyLong((ulong *)to_ptr, (ulong *)(popt + 2));
+			NetTimeOffset = ntohl(NetTimeOffset);
+			break;
+#endif
+		case 3:
+			NetCopyIP(&NetOurGatewayIP, (popt + 2));
+			break;
+		case 6:
+			NetCopyIP(&NetOurDNSIP, (popt + 2));
+#if defined(CONFIG_BOOTP_DNS2)
+			if (*(popt + 1) > 4)
+				NetCopyIP(&NetOurDNS2IP, (popt + 2 + 4));
+#endif
+			break;
+		case 12:
+			size = truncate_sz("Host Name",
+				sizeof(NetOurHostName), oplen);
+			memcpy(&NetOurHostName, popt + 2, size);
+			NetOurHostName[size] = 0;
+			break;
+		case 15:	/* Ignore Domain Name Option */
+			break;
+		case 17:
+			size = truncate_sz("Root Path",
+				sizeof(NetOurRootPath), oplen);
+			memcpy(&NetOurRootPath, popt + 2, size);
+			NetOurRootPath[size] = 0;
+			break;
+		case 28:	/* Ignore Broadcast Address Option */
+			break;
+#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
+		case 42:	/* NTP server IP */
+			NetCopyIP(&NetNtpServerIP, (popt + 2));
+			break;
+#endif
+		case 51:
+			NetCopyLong(&dhcp_leasetime, (ulong *) (popt + 2));
+			break;
+		case 53:	/* Ignore Message Type Option */
+			break;
+		case 54:
+			NetCopyIP(&NetDHCPServerIP, (popt + 2));
+			break;
+		case 58:	/* Ignore Renewal Time Option */
+			break;
+		case 59:	/* Ignore Rebinding Time Option */
+			break;
+		case 66:	/* Ignore TFTP server name */
+			break;
+		case 67:	/* vendor opt bootfile */
+			/*
+			 * I can't use dhcp_vendorex_proc here because I need
+			 * to write into the bootp packet - even then I had to
+			 * pass the bootp packet pointer into here as the
+			 * second arg
+			 */
+			size = truncate_sz("Opt Boot File",
+					    sizeof(bp->bp_file),
+					    oplen);
+			if (bp->bp_file[0] == '\0' && size > 0) {
+				/*
+				 * only use vendor boot file if we didn't
+				 * receive a boot file in the main non-vendor
+				 * part of the packet - god only knows why
+				 * some vendors chose not to use this perfectly
+				 * good spot to store the boot file (join on
+				 * Tru64 Unix) it seems mind bogglingly crazy
+				 * to me
+				 */
+				printf("*** WARNING: using vendor "
+					"optional boot file\n");
+				memcpy(bp->bp_file, popt + 2, size);
+				bp->bp_file[size] = '\0';
+			}
+			break;
+		default:
+#if defined(CONFIG_BOOTP_VENDOREX)
+			if (dhcp_vendorex_proc(popt))
+				break;
+#endif
+			printf("*** Unhandled DHCP Option in OFFER/ACK:"
+				" %d\n", *popt);
+			break;
+		}
+		popt += oplen + 2;	/* Process next option */
+	}
+}
+
+static int DhcpMessageType(unsigned char *popt)
+{
+	if (NetReadLong((ulong *)popt) != htonl(BOOTP_VENDOR_MAGIC))
+		return -1;
+
+	popt += 4;
+	while (*popt != 0xff) {
+		if (*popt == 53)	/* DHCP Message Type */
+			return *(popt + 2);
+		popt += *(popt + 1) + 2;	/* Scan through all options */
+	}
+	return -1;
+}
+
+static void DhcpSendRequestPkt(struct Bootp_t *bp_offer)
+{
+	uchar *pkt, *iphdr;
+	struct Bootp_t *bp;
+	int pktlen, iplen, extlen;
+	int eth_hdr_size;
+	IPaddr_t OfferedIP;
+
+	debug("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
+	pkt = NetTxPacket;
+	memset((void *)pkt, 0, PKTSIZE);
+
+	eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_IP);
+	pkt += eth_hdr_size;
+
+	iphdr = pkt;	/* We'll need this later to set proper pkt size */
+	pkt += IP_UDP_HDR_SIZE;
+
+	bp = (struct Bootp_t *)pkt;
+	bp->bp_op = OP_BOOTREQUEST;
+	bp->bp_htype = HWT_ETHER;
+	bp->bp_hlen = HWL_ETHER;
+	bp->bp_hops = 0;
+	bp->bp_secs = htons(get_timer(0) / 1000);
+	/* Do not set the client IP, your IP, or server IP yet, since it
+	 * hasn't been ACK'ed by the server yet */
+
+	/*
+	 * RFC3046 requires Relay Agents to discard packets with
+	 * nonzero and offered giaddr
+	 */
+	NetWriteIP(&bp->bp_giaddr, 0);
+
+	memcpy(bp->bp_chaddr, NetOurEther, 6);
+
+	/*
+	 * ID is the id of the OFFER packet
+	 */
+
+	NetCopyLong(&bp->bp_id, &bp_offer->bp_id);
+
+	/*
+	 * Copy options from OFFER packet if present
+	 */
+
+	/* Copy offered IP into the parameters request list */
+	NetCopyIP(&OfferedIP, &bp_offer->bp_yiaddr);
+	extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_REQUEST,
+		NetDHCPServerIP, OfferedIP);
+
+	iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen;
+	pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen;
+	net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
+
+#ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY
+	udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY);
+#endif	/* CONFIG_BOOTP_DHCP_REQUEST_DELAY */
+	debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
+	NetSendPacket(NetTxPacket, pktlen);
+}
+
+/*
+ *	Handle DHCP received packets.
+ */
+static void
+DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+	    unsigned len)
+{
+	struct Bootp_t *bp = (struct Bootp_t *)pkt;
+
+	debug("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
+		src, dest, len, dhcp_state);
+
+	/* Filter out pkts we don't want */
+	if (BootpCheckPkt(pkt, dest, src, len))
+		return;
+
+	debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state:"
+		" %d\n", src, dest, len, dhcp_state);
+
+	switch (dhcp_state) {
+	case SELECTING:
+		/*
+		 * Wait an appropriate time for any potential DHCPOFFER packets
+		 * to arrive.  Then select one, and generate DHCPREQUEST
+		 * response.  If filename is in format we recognize, assume it
+		 * is a valid OFFER from a server we want.
+		 */
+		debug("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file);
+#ifdef CONFIG_SYS_BOOTFILE_PREFIX
+		if (strncmp(bp->bp_file,
+			    CONFIG_SYS_BOOTFILE_PREFIX,
+			    strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) {
+#endif	/* CONFIG_SYS_BOOTFILE_PREFIX */
+
+			debug("TRANSITIONING TO REQUESTING STATE\n");
+			dhcp_state = REQUESTING;
+
+			if (NetReadLong((ulong *)&bp->bp_vend[0]) ==
+						htonl(BOOTP_VENDOR_MAGIC))
+				DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
+
+			NetSetTimeout(TIMEOUT, BootpTimeout);
+			DhcpSendRequestPkt(bp);
+#ifdef CONFIG_SYS_BOOTFILE_PREFIX
+		}
+#endif	/* CONFIG_SYS_BOOTFILE_PREFIX */
+
+		return;
+		break;
+	case REQUESTING:
+		debug("DHCP State: REQUESTING\n");
+
+		if (DhcpMessageType((u8 *)bp->bp_vend) == DHCP_ACK) {
+			if (NetReadLong((ulong *)&bp->bp_vend[0]) ==
+						htonl(BOOTP_VENDOR_MAGIC))
+				DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
+			/* Store net params from reply */
+			BootpCopyNetParams(bp);
+			dhcp_state = BOUND;
+			printf("DHCP client bound to address %pI4\n",
+				&NetOurIP);
+			bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP,
+				"bootp_stop");
+
+			net_auto_load();
+			return;
+		}
+		break;
+	case BOUND:
+		/* DHCP client bound to address */
+		break;
+	default:
+		puts("DHCP: INVALID STATE\n");
+		break;
+	}
+
+}
+
+void DhcpRequest(void)
+{
+	BootpRequest();
+}
+#endif	/* CONFIG_CMD_DHCP */
diff --git a/boot/common/src/uboot/net/bootp.h b/boot/common/src/uboot/net/bootp.h
new file mode 100644
index 0000000..ecbcc4d
--- /dev/null
+++ b/boot/common/src/uboot/net/bootp.h
@@ -0,0 +1,95 @@
+/*
+ *	Copied from LiMon - BOOTP.
+ *
+ *	Copyright 1994, 1995, 2000 Neil Russell.
+ *	(See License)
+ *	Copyright 2000 Paolo Scaffardi
+ */
+
+#ifndef __BOOTP_H__
+#define __BOOTP_H__
+
+#ifndef __NET_H__
+#include <net.h>
+#endif /* __NET_H__ */
+
+/**********************************************************************/
+
+/*
+ *	BOOTP header.
+ */
+#if defined(CONFIG_CMD_DHCP)
+/* Minimum DHCP Options size per RFC2131 - results in 576 byte pkt */
+#define OPT_FIELD_SIZE 312
+#if defined(CONFIG_BOOTP_VENDOREX)
+extern u8 *dhcp_vendorex_prep(u8 *e); /*rtn new e after add own opts. */
+extern u8 *dhcp_vendorex_proc(u8 *e); /*rtn next e if mine,else NULL  */
+#endif
+#else
+#define OPT_FIELD_SIZE 64
+#endif
+
+struct Bootp_t {
+	uchar		bp_op;		/* Operation			*/
+# define OP_BOOTREQUEST	1
+# define OP_BOOTREPLY	2
+	uchar		bp_htype;	/* Hardware type		*/
+# define HWT_ETHER	1
+	uchar		bp_hlen;	/* Hardware address length	*/
+# define HWL_ETHER	6
+	uchar		bp_hops;	/* Hop count (gateway thing)	*/
+	ulong		bp_id;		/* Transaction ID		*/
+	ushort		bp_secs;	/* Seconds since boot		*/
+	ushort		bp_spare1;	/* Alignment			*/
+	IPaddr_t	bp_ciaddr;	/* Client IP address		*/
+	IPaddr_t	bp_yiaddr;	/* Your (client) IP address	*/
+	IPaddr_t	bp_siaddr;	/* Server IP address		*/
+	IPaddr_t	bp_giaddr;	/* Gateway IP address		*/
+	uchar		bp_chaddr[16];	/* Client hardware address	*/
+	char		bp_sname[64];	/* Server host name		*/
+	char		bp_file[128];	/* Boot file name		*/
+	char		bp_vend[OPT_FIELD_SIZE]; /* Vendor information	*/
+};
+
+#define BOOTP_HDR_SIZE	sizeof(struct Bootp_t)
+
+/**********************************************************************/
+/*
+ *	Global functions and variables.
+ */
+
+/* bootp.c */
+extern ulong	BootpID;		/* ID of cur BOOTP request	*/
+extern char	BootFile[128];		/* Boot file name		*/
+extern int	BootpTry;
+
+
+/* Send a BOOTP request */
+extern void BootpRequest(void);
+
+/****************** DHCP Support *********************/
+extern void DhcpRequest(void);
+
+/* DHCP States */
+typedef enum { INIT,
+	       INIT_REBOOT,
+	       REBOOTING,
+	       SELECTING,
+	       REQUESTING,
+	       REBINDING,
+	       BOUND,
+	       RENEWING } dhcp_state_t;
+
+#define DHCP_DISCOVER 1
+#define DHCP_OFFER    2
+#define DHCP_REQUEST  3
+#define DHCP_DECLINE  4
+#define DHCP_ACK      5
+#define DHCP_NAK      6
+#define DHCP_RELEASE  7
+
+#define SELECT_TIMEOUT 3000UL	/* Milliseconds to wait for offers */
+
+/**********************************************************************/
+
+#endif /* __BOOTP_H__ */
diff --git a/boot/common/src/uboot/net/cdp.c b/boot/common/src/uboot/net/cdp.c
new file mode 100644
index 0000000..3d9559e
--- /dev/null
+++ b/boot/common/src/uboot/net/cdp.c
@@ -0,0 +1,366 @@
+/*
+ *	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, wd@denx.de
+ */
+
+#include <common.h>
+#include <net.h>
+#if defined(CONFIG_CDP_VERSION)
+#include <timestamp.h>
+#endif
+
+#include "cdp.h"
+
+/* Ethernet bcast address */
+const uchar NetCDPAddr[6] = { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
+
+#define CDP_DEVICE_ID_TLV		0x0001
+#define CDP_ADDRESS_TLV			0x0002
+#define CDP_PORT_ID_TLV			0x0003
+#define CDP_CAPABILITIES_TLV		0x0004
+#define CDP_VERSION_TLV			0x0005
+#define CDP_PLATFORM_TLV		0x0006
+#define CDP_NATIVE_VLAN_TLV		0x000a
+#define CDP_APPLIANCE_VLAN_TLV		0x000e
+#define CDP_TRIGGER_TLV			0x000f
+#define CDP_POWER_CONSUMPTION_TLV	0x0010
+#define CDP_SYSNAME_TLV			0x0014
+#define CDP_SYSOBJECT_TLV		0x0015
+#define CDP_MANAGEMENT_ADDRESS_TLV	0x0016
+
+#define CDP_TIMEOUT			250UL	/* one packet every 250ms */
+
+static int CDPSeq;
+static int CDPOK;
+
+ushort CDPNativeVLAN;
+ushort CDPApplianceVLAN;
+
+static const uchar CDP_SNAP_hdr[8] = {
+	0xAA, 0xAA, 0x03, 0x00, 0x00, 0x0C, 0x20, 0x00 };
+
+static ushort
+CDP_compute_csum(const uchar *buff, ushort len)
+{
+	ushort csum;
+	int     odd;
+	ulong   result = 0;
+	ushort  leftover;
+	ushort *p;
+
+	if (len > 0) {
+		odd = 1 & (ulong)buff;
+		if (odd) {
+			result = *buff << 8;
+			len--;
+			buff++;
+		}
+		while (len > 1) {
+			p = (ushort *)buff;
+			result += *p++;
+			buff = (uchar *)p;
+			if (result & 0x80000000)
+				result = (result & 0xFFFF) + (result >> 16);
+			len -= 2;
+		}
+		if (len) {
+			leftover = (signed short)(*(const signed char *)buff);
+			/*
+			 * CISCO SUCKS big time! (and blows too):
+			 * CDP uses the IP checksum algorithm with a twist;
+			 * for the last byte it *sign* extends and sums.
+			 */
+			result = (result & 0xffff0000) |
+				 ((result + leftover) & 0x0000ffff);
+		}
+		while (result >> 16)
+			result = (result & 0xFFFF) + (result >> 16);
+
+		if (odd)
+			result = ((result >> 8) & 0xff) |
+				 ((result & 0xff) << 8);
+	}
+
+	/* add up 16-bit and 17-bit words for 17+c bits */
+	result = (result & 0xffff) + (result >> 16);
+	/* add up 16-bit and 2-bit for 16+c bit */
+	result = (result & 0xffff) + (result >> 16);
+	/* add up carry.. */
+	result = (result & 0xffff) + (result >> 16);
+
+	/* negate */
+	csum = ~(ushort)result;
+
+	/* run time endian detection */
+	if (csum != htons(csum))	/* little endian */
+		csum = htons(csum);
+
+	return csum;
+}
+
+static int
+CDPSendTrigger(void)
+{
+	uchar *pkt;
+	ushort *s;
+	ushort *cp;
+	struct ethernet_hdr *et;
+	int len;
+	ushort chksum;
+#if	defined(CONFIG_CDP_DEVICE_ID) || defined(CONFIG_CDP_PORT_ID)   || \
+	defined(CONFIG_CDP_VERSION)   || defined(CONFIG_CDP_PLATFORM)
+	char buf[32];
+#endif
+
+	pkt = NetTxPacket;
+	et = (struct ethernet_hdr *)pkt;
+
+	/* NOTE: trigger sent not on any VLAN */
+
+	/* form ethernet header */
+	memcpy(et->et_dest, NetCDPAddr, 6);
+	memcpy(et->et_src, NetOurEther, 6);
+
+	pkt += ETHER_HDR_SIZE;
+
+	/* SNAP header */
+	memcpy((uchar *)pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr));
+	pkt += sizeof(CDP_SNAP_hdr);
+
+	/* CDP header */
+	*pkt++ = 0x02;				/* CDP version 2 */
+	*pkt++ = 180;				/* TTL */
+	s = (ushort *)pkt;
+	cp = s;
+	/* checksum (0 for later calculation) */
+	*s++ = htons(0);
+
+	/* CDP fields */
+#ifdef CONFIG_CDP_DEVICE_ID
+	*s++ = htons(CDP_DEVICE_ID_TLV);
+	*s++ = htons(CONFIG_CDP_DEVICE_ID);
+	sprintf(buf, CONFIG_CDP_DEVICE_ID_PREFIX "%pm", NetOurEther);
+	memcpy((uchar *)s, buf, 16);
+	s += 16 / 2;
+#endif
+
+#ifdef CONFIG_CDP_PORT_ID
+	*s++ = htons(CDP_PORT_ID_TLV);
+	memset(buf, 0, sizeof(buf));
+	sprintf(buf, CONFIG_CDP_PORT_ID, eth_get_dev_index());
+	len = strlen(buf);
+	if (len & 1)	/* make it even */
+		len++;
+	*s++ = htons(len + 4);
+	memcpy((uchar *)s, buf, len);
+	s += len / 2;
+#endif
+
+#ifdef CONFIG_CDP_CAPABILITIES
+	*s++ = htons(CDP_CAPABILITIES_TLV);
+	*s++ = htons(8);
+	*(ulong *)s = htonl(CONFIG_CDP_CAPABILITIES);
+	s += 2;
+#endif
+
+#ifdef CONFIG_CDP_VERSION
+	*s++ = htons(CDP_VERSION_TLV);
+	memset(buf, 0, sizeof(buf));
+	strcpy(buf, CONFIG_CDP_VERSION);
+	len = strlen(buf);
+	if (len & 1)	/* make it even */
+		len++;
+	*s++ = htons(len + 4);
+	memcpy((uchar *)s, buf, len);
+	s += len / 2;
+#endif
+
+#ifdef CONFIG_CDP_PLATFORM
+	*s++ = htons(CDP_PLATFORM_TLV);
+	memset(buf, 0, sizeof(buf));
+	strcpy(buf, CONFIG_CDP_PLATFORM);
+	len = strlen(buf);
+	if (len & 1)	/* make it even */
+		len++;
+	*s++ = htons(len + 4);
+	memcpy((uchar *)s, buf, len);
+	s += len / 2;
+#endif
+
+#ifdef CONFIG_CDP_TRIGGER
+	*s++ = htons(CDP_TRIGGER_TLV);
+	*s++ = htons(8);
+	*(ulong *)s = htonl(CONFIG_CDP_TRIGGER);
+	s += 2;
+#endif
+
+#ifdef CONFIG_CDP_POWER_CONSUMPTION
+	*s++ = htons(CDP_POWER_CONSUMPTION_TLV);
+	*s++ = htons(6);
+	*s++ = htons(CONFIG_CDP_POWER_CONSUMPTION);
+#endif
+
+	/* length of ethernet packet */
+	len = (uchar *)s - ((uchar *)NetTxPacket + ETHER_HDR_SIZE);
+	et->et_protlen = htons(len);
+
+	len = ETHER_HDR_SIZE + sizeof(CDP_SNAP_hdr);
+	chksum = CDP_compute_csum((uchar *)NetTxPacket + len,
+				  (uchar *)s - (NetTxPacket + len));
+	if (chksum == 0)
+		chksum = 0xFFFF;
+	*cp = htons(chksum);
+
+	NetSendPacket(NetTxPacket, (uchar *)s - NetTxPacket);
+	return 0;
+}
+
+static void
+CDPTimeout(void)
+{
+	CDPSeq++;
+
+	if (CDPSeq < 3) {
+		NetSetTimeout(CDP_TIMEOUT, CDPTimeout);
+		CDPSendTrigger();
+		return;
+	}
+
+	/* if not OK try again */
+	if (!CDPOK)
+		NetStartAgain();
+	else
+		net_set_state(NETLOOP_SUCCESS);
+}
+
+void cdp_receive(const uchar *pkt, unsigned len)
+{
+	const uchar *t;
+	const ushort *ss;
+	ushort type, tlen;
+	ushort vlan, nvlan;
+
+	/* minimum size? */
+	if (len < sizeof(CDP_SNAP_hdr) + 4)
+		goto pkt_short;
+
+	/* check for valid CDP SNAP header */
+	if (memcmp(pkt, CDP_SNAP_hdr, sizeof(CDP_SNAP_hdr)) != 0)
+		return;
+
+	pkt += sizeof(CDP_SNAP_hdr);
+	len -= sizeof(CDP_SNAP_hdr);
+
+	/* Version of CDP protocol must be >= 2 and TTL != 0 */
+	if (pkt[0] < 0x02 || pkt[1] == 0)
+		return;
+
+	/*
+	 * if version is greater than 0x02 maybe we'll have a problem;
+	 * output a warning
+	 */
+	if (pkt[0] != 0x02)
+		printf("**WARNING: CDP packet received with a protocol version "
+				"%d > 2\n", pkt[0] & 0xff);
+
+	if (CDP_compute_csum(pkt, len) != 0)
+		return;
+
+	pkt += 4;
+	len -= 4;
+
+	vlan = htons(-1);
+	nvlan = htons(-1);
+	while (len > 0) {
+		if (len < 4)
+			goto pkt_short;
+
+		ss = (const ushort *)pkt;
+		type = ntohs(ss[0]);
+		tlen = ntohs(ss[1]);
+		if (tlen > len)
+			goto pkt_short;
+
+		pkt += tlen;
+		len -= tlen;
+
+		ss += 2;	/* point ss to the data of the TLV */
+		tlen -= 4;
+
+		switch (type) {
+		case CDP_DEVICE_ID_TLV:
+			break;
+		case CDP_ADDRESS_TLV:
+			break;
+		case CDP_PORT_ID_TLV:
+			break;
+		case CDP_CAPABILITIES_TLV:
+			break;
+		case CDP_VERSION_TLV:
+			break;
+		case CDP_PLATFORM_TLV:
+			break;
+		case CDP_NATIVE_VLAN_TLV:
+			nvlan = *ss;
+			break;
+		case CDP_APPLIANCE_VLAN_TLV:
+			t = (const uchar *)ss;
+			while (tlen > 0) {
+				if (tlen < 3)
+					goto pkt_short;
+
+				ss = (const ushort *)(t + 1);
+
+#ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
+				if (t[0] == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
+					vlan = *ss;
+#else
+				/* XXX will this work; dunno */
+				vlan = ntohs(*ss);
+#endif
+				t += 3; tlen -= 3;
+			}
+			break;
+		case CDP_TRIGGER_TLV:
+			break;
+		case CDP_POWER_CONSUMPTION_TLV:
+			break;
+		case CDP_SYSNAME_TLV:
+			break;
+		case CDP_SYSOBJECT_TLV:
+			break;
+		case CDP_MANAGEMENT_ADDRESS_TLV:
+			break;
+		}
+	}
+
+	CDPApplianceVLAN = vlan;
+	CDPNativeVLAN = nvlan;
+
+	CDPOK = 1;
+	return;
+
+ pkt_short:
+	printf("** CDP packet is too short\n");
+	return;
+}
+
+void
+CDPStart(void)
+{
+	printf("Using %s device\n", eth_get_name());
+	CDPSeq = 0;
+	CDPOK = 0;
+
+	CDPNativeVLAN = htons(-1);
+	CDPApplianceVLAN = htons(-1);
+
+	NetSetTimeout(CDP_TIMEOUT, CDPTimeout);
+
+	CDPSendTrigger();
+}
diff --git a/boot/common/src/uboot/net/cdp.h b/boot/common/src/uboot/net/cdp.h
new file mode 100644
index 0000000..ec7315a
--- /dev/null
+++ b/boot/common/src/uboot/net/cdp.h
@@ -0,0 +1,21 @@
+/*
+ *	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, wd@denx.de
+ */
+
+#if defined(CONFIG_CMD_CDP)
+
+#ifndef __CDP_H__
+#define __CDP_H__
+
+void CDPStart(void);
+/* Process a received CDP packet */
+void cdp_receive(const uchar *pkt, unsigned len);
+
+#endif /* __CDP_H__ */
+#endif
diff --git a/boot/common/src/uboot/net/dns.c b/boot/common/src/uboot/net/dns.c
new file mode 100644
index 0000000..ff9ddff
--- /dev/null
+++ b/boot/common/src/uboot/net/dns.c
@@ -0,0 +1,206 @@
+/*
+ * DNS support driver
+ *
+ * Copyright (c) 2008 Pieter Voorthuijsen <pieter.voorthuijsen@prodrive.nl>
+ * Copyright (c) 2009 Robin Getz <rgetz@blackfin.uclinux.org>
+ *
+ * This is a simple DNS implementation for U-Boot. It will use the first IP
+ * in the DNS response as NetServerIP. This can then be used for any other
+ * network related activities.
+ *
+ * The packet handling is partly based on TADNS, original copyrights
+ * follow below.
+ *
+ */
+
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file.  As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <asm/unaligned.h>
+
+#include "dns.h"
+
+char *NetDNSResolve;	/* The host to resolve  */
+char *NetDNSenvvar;	/* The envvar to store the answer in */
+
+static int DnsOurPort;
+
+static void
+DnsSend(void)
+{
+	struct header *header;
+	int n, name_len;
+	uchar *p, *pkt;
+	const char *s;
+	const char *name;
+	enum dns_query_type qtype = DNS_A_RECORD;
+
+	name = NetDNSResolve;
+	pkt = p = (uchar *)(NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE);
+
+	/* Prepare DNS packet header */
+	header           = (struct header *) pkt;
+	header->tid      = 1;
+	header->flags    = htons(0x100);	/* standard query */
+	header->nqueries = htons(1);		/* Just one query */
+	header->nanswers = 0;
+	header->nauth    = 0;
+	header->nother   = 0;
+
+	/* Encode DNS name */
+	name_len = strlen(name);
+	p = (uchar *) &header->data;	/* For encoding host name into packet */
+
+	do {
+		s = strchr(name, '.');
+		if (!s)
+			s = name + name_len;
+
+		n = s - name;			/* Chunk length */
+		*p++ = n;			/* Copy length  */
+		memcpy(p, name, n);		/* Copy chunk   */
+		p += n;
+
+		if (*s == '.')
+			n++;
+
+		name += n;
+		name_len -= n;
+	} while (*s != '\0');
+
+	*p++ = 0;			/* Mark end of host name */
+	*p++ = 0;			/* Some servers require double null */
+	*p++ = (unsigned char) qtype;	/* Query Type */
+
+	*p++ = 0;
+	*p++ = 1;				/* Class: inet, 0x0001 */
+
+	n = p - pkt;				/* Total packet length */
+	debug("Packet size %d\n", n);
+
+	DnsOurPort = random_port();
+
+	NetSendUDPPacket(NetServerEther, NetOurDNSIP, DNS_SERVICE_PORT,
+		DnsOurPort, n);
+	debug("DNS packet sent\n");
+}
+
+static void
+DnsTimeout(void)
+{
+	puts("Timeout\n");
+	net_set_state(NETLOOP_FAIL);
+}
+
+static void
+DnsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
+{
+	struct header *header;
+	const unsigned char *p, *e, *s;
+	u16 type, i;
+	int found, stop, dlen;
+	char IPStr[22];
+	IPaddr_t IPAddress;
+
+
+	debug("%s\n", __func__);
+	if (dest != DnsOurPort)
+		return;
+
+	for (i = 0; i < len; i += 4)
+		debug("0x%p - 0x%.2x  0x%.2x  0x%.2x  0x%.2x\n",
+			pkt+i, pkt[i], pkt[i+1], pkt[i+2], pkt[i+3]);
+
+	/* We sent one query. We want to have a single answer: */
+	header = (struct header *) pkt;
+	if (ntohs(header->nqueries) != 1)
+		return;
+
+	/* Received 0 answers */
+	if (header->nanswers == 0) {
+		puts("DNS: host not found\n");
+		net_set_state(NETLOOP_SUCCESS);
+		return;
+	}
+
+	/* Skip host name */
+	s = &header->data[0];
+	e = pkt + len;
+	for (p = s; p < e && *p != '\0'; p++)
+		continue;
+
+	/* We sent query class 1, query type 1 */
+	if (&p[5] > e || get_unaligned_be16(p+1) != DNS_A_RECORD) {
+		puts("DNS: response was not an A record\n");
+		net_set_state(NETLOOP_SUCCESS);
+		return;
+	}
+
+	/* Go to the first answer section */
+	p += 5;
+
+	/* Loop through the answers, we want A type answer */
+	for (found = stop = 0; !stop && &p[12] < e; ) {
+
+		/* Skip possible name in CNAME answer */
+		if (*p != 0xc0) {
+			while (*p && &p[12] < e)
+				p++;
+			p--;
+		}
+		debug("Name (Offset in header): %d\n", p[1]);
+
+		type = get_unaligned_be16(p+2);
+		debug("type = %d\n", type);
+		if (type == DNS_CNAME_RECORD) {
+			/* CNAME answer. shift to the next section */
+			debug("Found canonical name\n");
+			dlen = get_unaligned_be16(p+10);
+			debug("dlen = %d\n", dlen);
+			p += 12 + dlen;
+		} else if (type == DNS_A_RECORD) {
+			debug("Found A-record\n");
+			found = stop = 1;
+		} else {
+			debug("Unknown type\n");
+			stop = 1;
+		}
+	}
+
+	if (found && &p[12] < e) {
+
+		dlen = get_unaligned_be16(p+10);
+		p += 12;
+		memcpy(&IPAddress, p, 4);
+
+		if (p + dlen <= e) {
+			ip_to_string(IPAddress, IPStr);
+			printf("%s\n", IPStr);
+			if (NetDNSenvvar)
+				setenv(NetDNSenvvar, IPStr);
+		} else
+			puts("server responded with invalid IP number\n");
+	}
+
+	net_set_state(NETLOOP_SUCCESS);
+}
+
+void
+DnsStart(void)
+{
+	debug("%s\n", __func__);
+
+	NetSetTimeout(DNS_TIMEOUT, DnsTimeout);
+	net_set_udp_handler(DnsHandler);
+
+	DnsSend();
+}
diff --git a/boot/common/src/uboot/net/dns.h b/boot/common/src/uboot/net/dns.h
new file mode 100644
index 0000000..277c093
--- /dev/null
+++ b/boot/common/src/uboot/net/dns.h
@@ -0,0 +1,39 @@
+/*
+ * (C) Masami Komiya <mkomiya@sonare.it> 2005
+ *  Copyright 2009, Robin Getz <rgetz@blackfin.uclinux.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+#ifndef __DNS_H__
+#define __DNS_H__
+
+#define DNS_SERVICE_PORT 53
+#define DNS_TIMEOUT      10000UL
+
+/* http://en.wikipedia.org/wiki/List_of_DNS_record_types */
+enum dns_query_type {
+	DNS_A_RECORD = 0x01,
+	DNS_CNAME_RECORD = 0x05,
+	DNS_MX_RECORD = 0x0f,
+};
+
+/*
+ * DNS network packet
+ */
+struct header {
+	uint16_t	tid;		/* Transaction ID */
+	uint16_t	flags;		/* Flags */
+	uint16_t	nqueries;	/* Questions */
+	uint16_t	nanswers;	/* Answers */
+	uint16_t	nauth;		/* Authority PRs */
+	uint16_t	nother;		/* Other PRs */
+	unsigned char	data[1];	/* Data, variable length */
+};
+
+extern void DnsStart(void);		/* Begin DNS */
+
+#endif
diff --git a/boot/common/src/uboot/net/eth.c b/boot/common/src/uboot/net/eth.c
new file mode 100644
index 0000000..ec382db
--- /dev/null
+++ b/boot/common/src/uboot/net/eth.c
@@ -0,0 +1,585 @@
+/*
+ * (C) Copyright 2001-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <asm/arch/gmac.h>
+
+
+void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
+{
+	char *end;
+	int i;
+
+	for (i = 0; i < 6; ++i) {
+		enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
+		if (addr)
+			addr = (*end) ? end + 1 : end;
+	}
+}
+
+int eth_getenv_enetaddr(char *name, uchar *enetaddr)
+{
+	eth_parse_enetaddr(getenv(name), enetaddr);
+	return is_valid_ether_addr(enetaddr);
+}
+
+int eth_setenv_enetaddr(char *name, const uchar *enetaddr)
+{
+	char buf[20];
+
+	sprintf(buf, "%pM", enetaddr);
+
+	return setenv(name, buf);
+}
+
+int eth_getenv_enetaddr_by_index(const char *base_name, int index,
+				 uchar *enetaddr)
+{
+	char enetvar[32];
+	if(index){
+		sprintf(enetvar, "%s%daddr", base_name, index);
+	}else{
+		sprintf(enetvar, "%saddr", base_name);
+	}
+	return eth_getenv_enetaddr(enetvar, enetaddr);
+}
+
+static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index,
+				 uchar *enetaddr)
+{
+	char enetvar[32];
+	if(index){
+		sprintf(enetvar, "%s%daddr", base_name, index);
+	}else{
+		sprintf(enetvar, "%saddr", base_name);
+	}
+	return eth_setenv_enetaddr(enetvar, enetaddr);
+}
+
+static int eth_mac_skip(int index)
+{
+	char enetvar[32];
+	char *skip_state;
+	if(index){
+		sprintf(enetvar, "eth%dmacskip", index);
+	}else{
+		sprintf(enetvar, "ethmacskip");
+	}
+	return ((skip_state = getenv(enetvar)) != NULL);
+}
+
+#ifdef CONFIG_RANDOM_MACADDR
+void eth_random_enetaddr(uchar *enetaddr)
+{
+	uint32_t rval;
+
+	srand(get_timer(0));
+
+	rval = rand();
+	enetaddr[0] = rval & 0xff;
+	enetaddr[1] = (rval >> 8) & 0xff;
+	enetaddr[2] = (rval >> 16) & 0xff;
+
+	rval = rand();
+	enetaddr[3] = rval & 0xff;
+	enetaddr[4] = (rval >> 8) & 0xff;
+	enetaddr[5] = (rval >> 16) & 0xff;
+
+	/* make sure it's local and unicast */
+	enetaddr[0] = (enetaddr[0] | 0x02) & ~0x01;
+}
+#endif
+
+/*
+ * CPU and board-specific Ethernet initializations.  Aliased function
+ * signals caller to move on
+ */
+static int __def_eth_init(bd_t *bis)
+{
+	return -1;
+}
+int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
+int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
+
+#ifdef CONFIG_API
+static struct {
+	uchar data[PKTSIZE];
+	int length;
+} eth_rcv_bufs[PKTBUFSRX];
+
+static unsigned int eth_rcv_current, eth_rcv_last;
+#endif
+
+static struct eth_device *eth_devices;
+struct eth_device *eth_current;
+
+struct eth_device *eth_get_dev_by_name(const char *devname)
+{
+	struct eth_device *dev, *target_dev;
+
+	BUG_ON(devname == NULL);
+
+	if (!eth_devices)
+		return NULL;
+
+	dev = eth_devices;
+	target_dev = NULL;
+	do {
+		if (strcmp(devname, dev->name) == 0) {
+			target_dev = dev;
+			break;
+		}
+		dev = dev->next;
+	} while (dev != eth_devices);
+
+	return target_dev;
+}
+
+struct eth_device *eth_get_dev_by_index(int index)
+{
+	struct eth_device *dev, *target_dev;
+
+	if (!eth_devices)
+		return NULL;
+
+	dev = eth_devices;
+	target_dev = NULL;
+	do {
+		if (dev->index == index) {
+			target_dev = dev;
+			break;
+		}
+		dev = dev->next;
+	} while (dev != eth_devices);
+
+	return target_dev;
+}
+
+int eth_get_dev_index(void)
+{
+	if (!eth_current)
+		return -1;
+
+	return eth_current->index;
+}
+
+static void eth_current_changed(void)
+{
+	char *act = getenv("ethact");
+	/* update current ethernet name */
+	if (eth_current) {
+		if (act == NULL || strcmp(act, eth_current->name) != 0)
+			setenv("ethact", eth_current->name);
+	}
+	/*
+	 * remove the variable completely if there is no active
+	 * interface
+	 */
+	else if (act != NULL)
+		setenv("ethact", NULL);
+}
+
+int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
+		   int eth_number)
+{
+	unsigned char env_enetaddr[6];
+	int ret = 0;
+
+	eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
+
+	if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {
+		if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) &&
+				memcmp(dev->enetaddr, env_enetaddr, 6)) {
+			printf("\nWarning: %s MAC addresses don't match:\n",
+				dev->name);
+			printf("Address in SROM is         %pM\n",
+				dev->enetaddr);
+			printf("Address in environment is  %pM\n",
+				env_enetaddr);
+		}
+
+		memcpy(dev->enetaddr, env_enetaddr, 6);
+	} else if (is_valid_ether_addr(dev->enetaddr)) {
+		eth_setenv_enetaddr_by_index(base_name, eth_number,
+					     dev->enetaddr);
+		printf("\nWarning: %s using MAC address from net device\n",
+			dev->name);
+	}
+
+	if (dev->write_hwaddr &&
+			!eth_mac_skip(eth_number)) {
+		if (!is_valid_ether_addr(dev->enetaddr))
+			return -1;
+
+		ret = dev->write_hwaddr(dev);
+	}
+
+	return ret;
+}
+
+int eth_register(struct eth_device *dev)
+{
+	struct eth_device *d;
+	static int index;
+
+	assert(strlen(dev->name) < sizeof(dev->name));
+
+	if (!eth_devices) {
+		eth_current = eth_devices = dev;
+		eth_current_changed();
+	} else {
+		for (d = eth_devices; d->next != eth_devices; d = d->next)
+			;
+		d->next = dev;
+	}
+
+	dev->state = ETH_STATE_INIT;
+	dev->next  = eth_devices;
+	dev->index = index++;
+
+	return 0;
+}
+
+int eth_unregister(struct eth_device *dev)
+{
+	struct eth_device *cur;
+
+	/* No device */
+	if (!eth_devices)
+		return -1;
+
+	for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
+	     cur = cur->next)
+		;
+
+	/* Device not found */
+	if (cur->next != dev)
+		return -1;
+
+	cur->next = dev->next;
+
+	if (eth_devices == dev)
+		eth_devices = dev->next == eth_devices ? NULL : dev->next;
+
+	if (eth_current == dev) {
+		eth_current = eth_devices;
+		eth_current_changed();
+	}
+
+	return 0;
+}
+
+static void eth_env_init(bd_t *bis)
+{
+	const char *s;
+
+	if ((s = getenv("bootfile")) != NULL)
+		copy_filename(BootFile, s, sizeof(BootFile));
+}
+
+int eth_initialize(bd_t *bis)
+{
+	int num_devices = 0;
+	eth_devices = NULL;
+	eth_current = NULL;
+
+	//bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
+	printf("bootstage net eth start\n");
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+	//miiphy_init();
+#endif
+
+#ifdef CONFIG_PHYLIB
+	//phy_init();
+#endif
+
+	gmac_phy_init();
+	eth_env_init(bis);
+
+	/*
+	 * If board-specific initialization exists, call it.
+	 * If not, call a CPU-specific one
+	 */
+	if (board_eth_init != __def_eth_init) {
+		if (board_eth_init(bis) < 0)
+			printf("Board Net Initialization Failed\n");
+	} else if (cpu_eth_init != __def_eth_init) {
+		if (cpu_eth_init(bis) < 0)
+			printf("CPU Net Initialization Failed\n");
+	} else
+		printf("Net Initialization Skipped\n");
+
+	if (!eth_devices) {
+		puts("No ethernet found.\n");
+		//bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
+	} else {
+		struct eth_device *dev = eth_devices;
+		char *ethprime = getenv("ethprime");
+
+		//bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
+		puts("bootstage net eth init\n");
+		do {
+			if (dev->index)
+				puts(", ");
+
+			printf("%s", dev->name);
+
+			if (ethprime && strcmp(dev->name, ethprime) == 0) {
+				eth_current = dev;
+				puts(" [PRIME]");
+			}
+
+			if (strchr(dev->name, ' '))
+				puts("\nWarning: eth device name has a space!"
+					"\n");
+
+			if (eth_write_hwaddr(dev, "eth", dev->index))
+				puts("\nWarning: failed to set MAC address\n");
+
+			dev = dev->next;
+			num_devices++;
+		} while (dev != eth_devices);
+
+		eth_current_changed();
+		putc('\n');
+	}
+
+	return num_devices;
+}
+
+#ifdef CONFIG_MCAST_TFTP
+/* Multicast.
+ * mcast_addr: multicast ipaddr from which multicast Mac is made
+ * join: 1=join, 0=leave.
+ */
+int eth_mcast_join(IPaddr_t mcast_ip, u8 join)
+{
+	u8 mcast_mac[6];
+	if (!eth_current || !eth_current->mcast)
+		return -1;
+	mcast_mac[5] = htonl(mcast_ip) & 0xff;
+	mcast_mac[4] = (htonl(mcast_ip)>>8) & 0xff;
+	mcast_mac[3] = (htonl(mcast_ip)>>16) & 0x7f;
+	mcast_mac[2] = 0x5e;
+	mcast_mac[1] = 0x0;
+	mcast_mac[0] = 0x1;
+	return eth_current->mcast(eth_current, mcast_mac, join);
+}
+
+/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
+ * and this is the ethernet-crc method needed for TSEC -- and perhaps
+ * some other adapter -- hash tables
+ */
+#define CRCPOLY_LE 0xedb88320
+u32 ether_crc(size_t len, unsigned char const *p)
+{
+	int i;
+	u32 crc;
+	crc = ~0;
+	while (len--) {
+		crc ^= *p++;
+		for (i = 0; i < 8; i++)
+			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+	}
+	/* an reverse the bits, cuz of way they arrive -- last-first */
+	crc = (crc >> 16) | (crc << 16);
+	crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
+	crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
+	crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
+	crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
+	return crc;
+}
+
+#endif
+
+
+int eth_init(bd_t *bis)
+{
+	struct eth_device *old_current, *dev;
+
+	if (!eth_current) {
+		puts("No ethernet found.\n");
+		return -1;
+	}
+
+	/* Sync environment with network devices */
+	dev = eth_devices;
+	do {
+		uchar env_enetaddr[6];
+
+		if (eth_getenv_enetaddr_by_index("eth", dev->index,
+						 env_enetaddr))
+			memcpy(dev->enetaddr, env_enetaddr, 6);
+
+		dev = dev->next;
+	} while (dev != eth_devices);
+
+	old_current = eth_current;
+	do {
+		debug("Trying %s\n", eth_current->name);
+
+		if (eth_current->init(eth_current, bis) >= 0) {
+			eth_current->state = ETH_STATE_ACTIVE;
+
+			return 0;
+		}
+		debug("FAIL\n");
+
+		eth_try_another(0);
+	} while (old_current != eth_current);
+
+	return -1;
+}
+
+void eth_halt(void)
+{
+	if (!eth_current)
+		return;
+
+	eth_current->halt(eth_current);
+
+	eth_current->state = ETH_STATE_PASSIVE;
+}
+
+int eth_send(void *packet, int length)
+{
+	if (!eth_current)
+		return -1;
+
+	return eth_current->send(eth_current, packet, length);
+}
+
+int eth_rx(void)
+{
+	if (!eth_current)
+		return -1;
+
+	return eth_current->recv(eth_current);
+}
+
+#ifdef CONFIG_API
+static void eth_save_packet(void *packet, int length)
+{
+	char *p = packet;
+	int i;
+
+	if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
+		return;
+
+	if (PKTSIZE < length)
+		return;
+
+	for (i = 0; i < length; i++)
+		eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
+
+	eth_rcv_bufs[eth_rcv_last].length = length;
+	eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
+}
+
+int eth_receive(void *packet, int length)
+{
+	char *p = packet;
+	void *pp = push_packet;
+	int i;
+
+	if (eth_rcv_current == eth_rcv_last) {
+		push_packet = eth_save_packet;
+		eth_rx();
+		push_packet = pp;
+
+		if (eth_rcv_current == eth_rcv_last)
+			return -1;
+	}
+
+	length = min(eth_rcv_bufs[eth_rcv_current].length, length);
+
+	for (i = 0; i < length; i++)
+		p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
+
+	eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
+	return length;
+}
+#endif /* CONFIG_API */
+
+void eth_try_another(int first_restart)
+{
+	static struct eth_device *first_failed;
+	char *ethrotate;
+
+	/*
+	 * Do not rotate between network interfaces when
+	 * 'ethrotate' variable is set to 'no'.
+	 */
+	ethrotate = getenv("ethrotate");
+	if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
+		return;
+
+	if (!eth_current)
+		return;
+
+	if (first_restart)
+		first_failed = eth_current;
+
+	eth_current = eth_current->next;
+
+	eth_current_changed();
+
+	if (first_failed == eth_current)
+		NetRestartWrap = 1;
+}
+
+void eth_set_current(void)
+{
+	static char *act;
+	static int  env_changed_id;
+	struct eth_device *old_current;
+	int	env_id;
+
+	if (!eth_current)	/* XXX no current */
+		return;
+
+	env_id = get_env_id();
+	if ((act == NULL) || (env_changed_id != env_id)) {
+		act = getenv("ethact");
+		env_changed_id = env_id;
+	}
+	if (act != NULL) {
+		old_current = eth_current;
+		do {
+			if (strcmp(eth_current->name, act) == 0)
+				return;
+			eth_current = eth_current->next;
+		} while (old_current != eth_current);
+	}
+
+	eth_current_changed();
+}
+
+char *eth_get_name(void)
+{
+	return eth_current ? eth_current->name : "unknown";
+}
diff --git a/boot/common/src/uboot/net/link_local.c b/boot/common/src/uboot/net/link_local.c
new file mode 100644
index 0000000..1ba796e
--- /dev/null
+++ b/boot/common/src/uboot/net/link_local.c
@@ -0,0 +1,336 @@
+/*
+ * RFC3927 ZeroConf IPv4 Link-Local addressing
+ * (see <http://www.zeroconf.org/>)
+ *
+ * Copied from BusyBox - networking/zcip.c
+ *
+ * Copyright (C) 2003 by Arthur van Hoff (avh@strangeberry.com)
+ * Copyright (C) 2004 by David Brownell
+ * Copyright (C) 2010 by Joe Hershberger
+ *
+ * Licensed under the GPL v2 or later
+ */
+
+#include <common.h>
+#include <net.h>
+#include "arp.h"
+#include "net_rand.h"
+
+/* We don't need more than 32 bits of the counter */
+#define MONOTONIC_MS() ((unsigned)get_timer(0) * (1000 / CONFIG_SYS_HZ))
+
+enum {
+/* 169.254.0.0 */
+	LINKLOCAL_ADDR = 0xa9fe0000,
+
+	IN_CLASSB_NET = 0xffff0000,
+	IN_CLASSB_HOST = 0x0000ffff,
+
+/* protocol timeout parameters, specified in seconds */
+	PROBE_WAIT = 1,
+	PROBE_MIN = 1,
+	PROBE_MAX = 2,
+	PROBE_NUM = 3,
+	MAX_CONFLICTS = 10,
+	RATE_LIMIT_INTERVAL = 60,
+	ANNOUNCE_WAIT = 2,
+	ANNOUNCE_NUM = 2,
+	ANNOUNCE_INTERVAL = 2,
+	DEFEND_INTERVAL = 10
+};
+
+/* States during the configuration process. */
+static enum ll_state_t {
+	PROBE = 0,
+	RATE_LIMIT_PROBE,
+	ANNOUNCE,
+	MONITOR,
+	DEFEND,
+	DISABLED
+} state = DISABLED;
+
+static IPaddr_t ip;
+static int timeout_ms = -1;
+static unsigned deadline_ms;
+static unsigned conflicts;
+static unsigned nprobes;
+static unsigned nclaims;
+static int ready;
+static unsigned int seed;
+
+static void link_local_timeout(void);
+
+/**
+ * Pick a random link local IP address on 169.254/16, except that
+ * the first and last 256 addresses are reserved.
+ */
+static IPaddr_t pick(void)
+{
+	unsigned tmp;
+
+	do {
+		tmp = rand_r(&seed) & IN_CLASSB_HOST;
+	} while (tmp > (IN_CLASSB_HOST - 0x0200));
+	return (IPaddr_t) htonl((LINKLOCAL_ADDR + 0x0100) + tmp);
+}
+
+/**
+ * Return milliseconds of random delay, up to "secs" seconds.
+ */
+static inline unsigned random_delay_ms(unsigned secs)
+{
+	return rand_r(&seed) % (secs * 1000);
+}
+
+static void configure_wait(void)
+{
+	if (timeout_ms == -1)
+		return;
+
+	/* poll, being ready to adjust current timeout */
+	if (!timeout_ms)
+		timeout_ms = random_delay_ms(PROBE_WAIT);
+
+	/* set deadline_ms to the point in time when we timeout */
+	deadline_ms = MONOTONIC_MS() + timeout_ms;
+
+	debug_cond(DEBUG_DEV_PKT, "...wait %d %s nprobes=%u, nclaims=%u\n",
+			timeout_ms, eth_get_name(), nprobes, nclaims);
+
+	NetSetTimeout(timeout_ms, link_local_timeout);
+}
+
+void link_local_start(void)
+{
+	ip = getenv_IPaddr("llipaddr");
+	if (ip != 0 && (ntohl(ip) & IN_CLASSB_NET) != LINKLOCAL_ADDR) {
+		puts("invalid link address");
+		net_set_state(NETLOOP_FAIL);
+		return;
+	}
+	NetOurSubnetMask = IN_CLASSB_NET;
+
+	seed = seed_mac();
+	if (ip == 0)
+		ip = pick();
+
+	state = PROBE;
+	timeout_ms = 0;
+	conflicts = 0;
+	nprobes = 0;
+	nclaims = 0;
+	ready = 0;
+
+	configure_wait();
+}
+
+static void link_local_timeout(void)
+{
+	switch (state) {
+	case PROBE:
+		/* timeouts in the PROBE state mean no conflicting ARP packets
+		   have been received, so we can progress through the states */
+		if (nprobes < PROBE_NUM) {
+			nprobes++;
+			debug_cond(DEBUG_LL_STATE, "probe/%u %s@%pI4\n",
+					nprobes, eth_get_name(), &ip);
+			arp_raw_request(0, NetEtherNullAddr, ip);
+			timeout_ms = PROBE_MIN * 1000;
+			timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN);
+		} else {
+			/* Switch to announce state */
+			state = ANNOUNCE;
+			nclaims = 0;
+			debug_cond(DEBUG_LL_STATE, "announce/%u %s@%pI4\n",
+					nclaims, eth_get_name(), &ip);
+			arp_raw_request(ip, NetOurEther, ip);
+			timeout_ms = ANNOUNCE_INTERVAL * 1000;
+		}
+		break;
+	case RATE_LIMIT_PROBE:
+		/* timeouts in the RATE_LIMIT_PROBE state mean no conflicting
+		   ARP packets have been received, so we can move immediately
+		   to the announce state */
+		state = ANNOUNCE;
+		nclaims = 0;
+		debug_cond(DEBUG_LL_STATE, "announce/%u %s@%pI4\n",
+				nclaims, eth_get_name(), &ip);
+		arp_raw_request(ip, NetOurEther, ip);
+		timeout_ms = ANNOUNCE_INTERVAL * 1000;
+		break;
+	case ANNOUNCE:
+		/* timeouts in the ANNOUNCE state mean no conflicting ARP
+		   packets have been received, so we can progress through
+		   the states */
+		if (nclaims < ANNOUNCE_NUM) {
+			nclaims++;
+			debug_cond(DEBUG_LL_STATE, "announce/%u %s@%pI4\n",
+					nclaims, eth_get_name(), &ip);
+			arp_raw_request(ip, NetOurEther, ip);
+			timeout_ms = ANNOUNCE_INTERVAL * 1000;
+		} else {
+			/* Switch to monitor state */
+			state = MONITOR;
+			printf("Successfully assigned %pI4\n", &ip);
+			NetCopyIP(&NetOurIP, &ip);
+			ready = 1;
+			conflicts = 0;
+			timeout_ms = -1;
+			/* Never timeout in the monitor state */
+			NetSetTimeout(0, NULL);
+
+			/* NOTE: all other exit paths should deconfig ... */
+			net_set_state(NETLOOP_SUCCESS);
+			return;
+		}
+		break;
+	case DEFEND:
+		/* We won!  No ARP replies, so just go back to monitor */
+		state = MONITOR;
+		timeout_ms = -1;
+		conflicts = 0;
+		break;
+	default:
+		/* Invalid, should never happen.  Restart the whole protocol */
+		state = PROBE;
+		ip = pick();
+		timeout_ms = 0;
+		nprobes = 0;
+		nclaims = 0;
+		break;
+	}
+	configure_wait();
+}
+
+void link_local_receive_arp(struct arp_hdr *arp, int len)
+{
+	int source_ip_conflict;
+	int target_ip_conflict;
+
+	if (state == DISABLED)
+		return;
+
+	/* We need to adjust the timeout in case we didn't receive a
+	   conflicting packet. */
+	if (timeout_ms > 0) {
+		unsigned diff = deadline_ms - MONOTONIC_MS();
+		if ((int)(diff) < 0) {
+			/* Current time is greater than the expected timeout
+			   time. This should never happen */
+			debug_cond(DEBUG_LL_STATE,
+				"missed an expected timeout\n");
+			timeout_ms = 0;
+		} else {
+			debug_cond(DEBUG_INT_STATE, "adjusting timeout\n");
+			timeout_ms = diff | 1; /* never 0 */
+		}
+	}
+#if 0
+ /* XXX Don't bother with ethernet link just yet */
+	if ((fds[0].revents & POLLIN) == 0) {
+		if (fds[0].revents & POLLERR) {
+			/*
+			 * FIXME: links routinely go down;
+			 */
+			bb_error_msg("iface %s is down", eth_get_name());
+			if (ready) {
+				run(argv, "deconfig", &ip);
+			}
+			return EXIT_FAILURE;
+		}
+		continue;
+	}
+#endif
+
+	debug_cond(DEBUG_INT_STATE, "%s recv arp type=%d, op=%d,\n",
+		eth_get_name(), ntohs(arp->ar_pro),
+		ntohs(arp->ar_op));
+	debug_cond(DEBUG_INT_STATE, "\tsource=%pM %pI4\n",
+		&arp->ar_sha,
+		&arp->ar_spa);
+	debug_cond(DEBUG_INT_STATE, "\ttarget=%pM %pI4\n",
+		&arp->ar_tha,
+		&arp->ar_tpa);
+
+	if (arp->ar_op != htons(ARPOP_REQUEST)
+	 && arp->ar_op != htons(ARPOP_REPLY)
+	) {
+		configure_wait();
+		return;
+	}
+
+	source_ip_conflict = 0;
+	target_ip_conflict = 0;
+
+	if (memcmp(&arp->ar_spa, &ip, ARP_PLEN) == 0
+	 && memcmp(&arp->ar_sha, NetOurEther, ARP_HLEN) != 0
+	) {
+		source_ip_conflict = 1;
+	}
+	if (arp->ar_op == htons(ARPOP_REQUEST)
+	 && memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0
+	 && memcmp(&arp->ar_tha, NetOurEther, ARP_HLEN) != 0
+	) {
+		target_ip_conflict = 1;
+	}
+
+	debug_cond(DEBUG_NET_PKT,
+		"state = %d, source ip conflict = %d, target ip conflict = "
+		"%d\n", state, source_ip_conflict, target_ip_conflict);
+	switch (state) {
+	case PROBE:
+	case ANNOUNCE:
+		/* When probing or announcing, check for source IP conflicts
+		   and other hosts doing ARP probes (target IP conflicts). */
+		if (source_ip_conflict || target_ip_conflict) {
+			conflicts++;
+			state = PROBE;
+			if (conflicts >= MAX_CONFLICTS) {
+				debug("%s ratelimit\n", eth_get_name());
+				timeout_ms = RATE_LIMIT_INTERVAL * 1000;
+				state = RATE_LIMIT_PROBE;
+			}
+
+			/* restart the whole protocol */
+			ip = pick();
+			timeout_ms = 0;
+			nprobes = 0;
+			nclaims = 0;
+		}
+		break;
+	case MONITOR:
+		/* If a conflict, we try to defend with a single ARP probe */
+		if (source_ip_conflict) {
+			debug("monitor conflict -- defending\n");
+			state = DEFEND;
+			timeout_ms = DEFEND_INTERVAL * 1000;
+			arp_raw_request(ip, NetOurEther, ip);
+		}
+		break;
+	case DEFEND:
+		/* Well, we tried.  Start over (on conflict) */
+		if (source_ip_conflict) {
+			state = PROBE;
+			debug("defend conflict -- starting over\n");
+			ready = 0;
+			NetOurIP = 0;
+
+			/* restart the whole protocol */
+			ip = pick();
+			timeout_ms = 0;
+			nprobes = 0;
+			nclaims = 0;
+		}
+		break;
+	default:
+		/* Invalid, should never happen.  Restart the whole protocol */
+		debug("invalid state -- starting over\n");
+		state = PROBE;
+		ip = pick();
+		timeout_ms = 0;
+		nprobes = 0;
+		nclaims = 0;
+		break;
+	}
+	configure_wait();
+}
diff --git a/boot/common/src/uboot/net/link_local.h b/boot/common/src/uboot/net/link_local.h
new file mode 100644
index 0000000..bb99816
--- /dev/null
+++ b/boot/common/src/uboot/net/link_local.h
@@ -0,0 +1,24 @@
+/*
+ * RFC3927 ZeroConf IPv4 Link-Local addressing
+ * (see <http://www.zeroconf.org/>)
+ *
+ * Copied from BusyBox - networking/zcip.c
+ *
+ * Copyright (C) 2003 by Arthur van Hoff (avh@strangeberry.com)
+ * Copyright (C) 2004 by David Brownell
+ *
+ * Licensed under the GPL v2 or later
+ */
+
+#if defined(CONFIG_CMD_LINK_LOCAL)
+
+#ifndef __LINK_LOCAL_H__
+#define __LINK_LOCAL_H__
+
+#include <common.h>
+
+void link_local_receive_arp(struct arp_hdr *arp, int len);
+void link_local_start(void);
+
+#endif /* __LINK_LOCAL_H__ */
+#endif
diff --git a/boot/common/src/uboot/net/net.c b/boot/common/src/uboot/net/net.c
new file mode 100644
index 0000000..bc3bc25
--- /dev/null
+++ b/boot/common/src/uboot/net/net.c
@@ -0,0 +1,1512 @@
+/*
+ *	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, wd@denx.de
+ */
+
+/*
+ * 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
+ */
+
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <net.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 "ping.h"
+#include "rarp.h"
+#if defined(CONFIG_CMD_SNTP)
+#include "sntp.h"
+#endif
+#include "tftp.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+
+/** BOOTP EXTENTIONS **/
+
+/* Our subnet mask (0=unknown) */
+IPaddr_t	NetOurSubnetMask;
+/* Our gateways IP address */
+IPaddr_t	NetOurGatewayIP;
+/* Our DNS IP address */
+IPaddr_t	NetOurDNSIP;
+#if defined(CONFIG_BOOTP_DNS2)
+/* Our 2nd DNS IP address */
+IPaddr_t	NetOurDNS2IP;
+#endif
+/* Our NIS domain */
+char		NetOurNISDomain[32] = {0,};
+/* Our hostname */
+char		NetOurHostName[32] = {0,};
+/* Our bootpath */
+char		NetOurRootPath[64] = {0,};
+/* Our bootfile size in blocks */
+ushort		NetBootFileSize;
+extern int arp_cnt;
+extern int tftp_server_cnt;
+
+#ifdef CONFIG_MCAST_TFTP	/* Multicast TFTP */
+IPaddr_t Mcast_addr;
+#endif
+
+/** END OF BOOTP EXTENTIONS **/
+
+/* The actual transferred size of the bootfile (in bytes) */
+ulong		NetBootFileXferSize;
+/* Our ethernet address */
+uchar		NetOurEther[6];
+/* Boot server enet address */
+uchar		NetServerEther[6];
+/* Our IP addr (0 = unknown) */
+IPaddr_t	NetOurIP;
+/* Server IP addr (0 = unknown) */
+IPaddr_t	NetServerIP;
+/* Current receive packet */
+uchar *NetRxPacket;
+/* Current rx packet length */
+int		NetRxPacketLen;
+/* IP packet ID */
+unsigned	NetIPID;
+/* Ethernet bcast address */
+uchar		NetBcastAddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+uchar		NetEtherNullAddr[6];
+#ifdef CONFIG_API
+void		(*push_packet)(void *, int len) = 0;
+#endif
+/* Network loop state */
+enum net_loop_state net_state;
+/* Tried all network devices */
+int		NetRestartWrap;
+/* Network loop restarted */
+static int	NetRestarted;
+/* At least one device configured */
+static int	NetDevExists;
+
+/* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
+/* default is without VLAN */
+ushort		NetOurVLAN = 0xFFFF;
+/* ditto */
+ushort		NetOurNativeVLAN = 0xFFFF;
+
+/* Boot File name */
+char		BootFile[128];
+
+#if defined(CONFIG_CMD_SNTP)
+/* NTP server IP address */
+IPaddr_t	NetNtpServerIP;
+/* offset time from UTC */
+int		NetTimeOffset;
+#endif
+
+static uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
+
+/* Receive packet */
+uchar *NetRxPackets[PKTBUFSRX];
+
+/* 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 *timeHandler;
+/* Time base value */
+static ulong	timeStart;
+/* Current timeout value */
+static ulong	timeDelta;
+/* THE transmit packet */
+uchar *NetTxPacket;
+ulong  time_over = 0;
+extern uint32_t  g_gmac_init_overtime;
+
+static int net_check_prereq(enum proto_t protocol);
+
+static int NetTryCount;
+
+/**********************************************************************/
+
+static int on_bootfile(const char *name, const char *value, enum env_op op,
+	int flags)
+{
+	switch (op) {
+	case env_op_create:
+	case env_op_overwrite:
+		copy_filename(BootFile, value, sizeof(BootFile));
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+U_BOOT_ENV_CALLBACK(bootfile, on_bootfile);
+
+/*
+ * 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.
+		 */
+		NfsStart();
+		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;
+	}
+	TftpStart(TFTPGET);
+}
+
+static void NetInitLoop(void)
+{
+	static int env_changed_id;
+	int env_id = get_env_id();
+
+	/* update only when the environment has changed */
+	if (env_changed_id != env_id) {
+		NetOurIP = getenv_IPaddr("ipaddr");
+		NetOurGatewayIP = getenv_IPaddr("gatewayip");
+		NetOurSubnetMask = getenv_IPaddr("netmask");
+		NetServerIP = getenv_IPaddr("serverip");
+		NetOurNativeVLAN = getenv_VLAN("nvlan");
+		NetOurVLAN = getenv_VLAN("vlan");
+#if defined(CONFIG_CMD_DNS)
+		NetOurDNSIP = getenv_IPaddr("dnsip");
+#endif
+		env_changed_id = env_id;
+	}
+	memcpy(NetOurEther, eth_get_dev()->enetaddr, 6);
+
+	return;
+}
+
+static void net_clear_handlers(void)
+{
+	net_set_udp_handler(NULL);
+	net_set_arp_handler(NULL);
+	NetSetTimeout(0, NULL);
+}
+
+static void net_cleanup_loop(void)
+{
+	net_clear_handlers();
+}
+
+void net_init(void)
+{
+	static int first_call = 1;
+	/* overtime 15s*/
+       time_over = g_gmac_init_overtime*100000UL;
+	if (first_call) {
+		/*
+		 *	Setup packet buffers, aligned correctly.
+		 */
+		int i;
+
+		NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
+		NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
+		for (i = 0; i < PKTBUFSRX; i++)
+			NetRxPackets[i] = NetTxPacket + (i + 1) * PKTSIZE_ALIGN;
+
+		ArpInit();
+		net_clear_handlers();
+
+		/* Only need to setup buffer pointers once. */
+		first_call = 0;
+	}
+
+	NetInitLoop();
+}
+
+/**********************************************************************/
+/*
+ *	Main network processing loop.
+ */
+
+int NetLoop(enum proto_t protocol)
+{
+	bd_t *bd = gd->bd;
+	int ret = -1;
+	int i = 0;
+
+	NetRestarted = 0;
+	NetDevExists = 0;
+	NetTryCount = 1;
+	debug_cond(DEBUG_INT_STATE, "--- NetLoop Entry\n");
+
+	//bootstage_mark_name(BOOTSTAGE_ID_ETH_START, "eth_start");
+	debug("eth_start\n");
+	net_init();
+	
+	if (eth_is_on_demand_init() || protocol != NETCONS)
+	//if (protocol != NETCONS)
+	{
+		//eth_halt();  //wl: for test
+		eth_set_current();
+		if (eth_init(bd) < 0) {
+			eth_halt();
+			return -1;
+		}
+	} else
+		eth_init_state_only(bd);
+
+restart:
+	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, "--- NetLoop Init\n");
+	//debug("NetLoop Init\n");
+	NetInitLoop();
+
+	switch (net_check_prereq(protocol)) {
+	case 1:
+		/* network not configured */
+		eth_halt();
+		return -1;
+
+	case 2:
+		/* network device not configured */
+		break;
+
+	case 0:
+		NetDevExists = 1;
+		NetBootFileXferSize = 0;
+		switch (protocol) {
+		case TFTPGET:
+#ifdef CONFIG_CMD_TFTPPUT
+		case TFTPPUT:
+#endif
+			/* always use ARP to get server ethernet address */
+			TftpStart(protocol);
+			break;
+#ifdef CONFIG_CMD_TFTPSRV
+		case TFTPSRV:
+			TftpStartServer();
+			break;
+#endif
+#if defined(CONFIG_CMD_DHCP)
+		case DHCP:
+			BootpTry = 0;
+			NetOurIP = 0;
+			DhcpRequest();		/* Basically same as BOOTP */
+			break;
+#endif
+
+		case BOOTP:
+			BootpTry = 0;
+			NetOurIP = 0;
+			BootpRequest();
+			break;
+
+#if defined(CONFIG_CMD_RARP)
+		case RARP:
+			RarpTry = 0;
+			NetOurIP = 0;
+			
+			RarpRequest();
+			break;
+#endif
+#if defined(CONFIG_CMD_PING)
+		case PING:
+			ping_start();
+			break;
+#endif
+#if defined(CONFIG_CMD_NFS)
+		case NFS:
+			NfsStart();
+			break;
+#endif
+#if defined(CONFIG_CMD_CDP)
+		case CDP:
+			CDPStart();
+			break;
+#endif
+#ifdef CONFIG_NETCONSOLE
+		case NETCONS:
+			NcStart();
+			break;
+#endif
+#if defined(CONFIG_CMD_SNTP)
+		case SNTP:
+			SntpStart();
+			break;
+#endif
+#if defined(CONFIG_CMD_DNS)
+		case DNS:
+			DnsStart();
+			break;
+#endif
+#if defined(CONFIG_CMD_LINK_LOCAL)
+		case LINKLOCAL:
+			link_local_start();
+			break;
+#endif
+		default:
+			break;
+		}
+
+		break;
+	}
+	
+//for(i=0;i<1000;i++);
+//eth_rx();
+#if 0	
+#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, ... */
+#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
+		/*
+		 *	Check the ethernet for a new packet.  The ethernet
+		 *	receive routine will process it.
+		 */
+		eth_rx();
+
+		/*
+		 *	Abort if ctrl-c was pressed.
+		 */
+		if (ctrlc()) {
+			/* cancel any ARP that may not have completed */
+			NetArpWaitPacketIP = 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, "--- NetLoop Abort!\n");
+			printf("--- NetLoop Abort!\n");
+			goto done;
+		}
+
+		ArpTimeoutCheck();
+		if(arp_cnt> 9  || tftp_server_cnt>1)
+			{
+          break;
+		}
+	
+
+		/*
+		 *	Check for a timeout, and run the timeout handler
+		 *	if we have one.
+		 */
+		if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) {
+			thand_f *x;
+#if 0
+#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_SYS_FAULT_ECHO_LINK_DOWN, ... */
+#endif /* CONFIG_MII, ... */
+			//debug_cond(DEBUG_INT_STATE, "--- NetLoop timeout\n");
+			printf("--- NetLoop timeout\n");
+			x = timeHandler;
+			timeHandler = (thand_f *)0;
+			(*x)();
+		}
+
+
+		switch (net_state) {
+
+		case NETLOOP_RESTART:
+			NetRestarted = 1;
+			goto restart;
+
+		case NETLOOP_SUCCESS:
+			net_cleanup_loop();
+			if (NetBootFileXferSize > 0) {
+				printf("Bytes transferred = %ld (%lx hex)\n",
+					NetBootFileXferSize,
+					NetBootFileXferSize);
+				setenv_hex("filesize", NetBootFileXferSize);
+				setenv_hex("fileaddr", load_addr);
+			}
+			if (protocol != NETCONS)
+				eth_halt();
+			else
+				eth_halt_state_only();
+
+			//eth_set_last_protocol(protocol);
+
+			ret = NetBootFileXferSize;
+			//debug_cond(DEBUG_INT_STATE, "--- NetLoop Success!\n");
+			printf("--- NetLoop Success!\n");
+			goto done;
+
+		case NETLOOP_FAIL:
+			net_cleanup_loop();
+			/* Invalidate the last protocol */
+			eth_set_last_protocol(BOOTP);
+			//debug_cond(DEBUG_INT_STATE, "--- NetLoop Fail!\n");
+			printf("--- NetLoop Fail!\n");
+			goto done;
+
+		case NETLOOP_CONTINUE:
+			continue;
+		}
+	}
+
+done:
+#ifdef CONFIG_CMD_TFTPPUT
+	/* Clear out the handlers */
+	net_set_udp_handler(NULL);
+	net_set_icmp_handler(NULL);
+#endif
+	return ret;
+}
+
+/**********************************************************************/
+
+static void
+startAgainTimeout(void)
+{
+	net_set_state(NETLOOP_RESTART);
+}
+
+void NetStartAgain(void)
+{
+	char *nretry;
+	int retry_forever = 0;
+	unsigned long retrycnt = 0;
+
+	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
+		retry_forever = 1;
+
+	if ((!retry_forever) && (NetTryCount >= retrycnt)) {
+		eth_halt();
+		net_set_state(NETLOOP_FAIL);
+		return;
+	}
+
+	NetTryCount++;
+
+	eth_halt();
+#if !defined(CONFIG_NET_DO_NOT_TRY_ANOTHER)
+	eth_try_another(!NetRestarted);
+#endif
+	eth_init(gd->bd);
+	if (NetRestartWrap) {
+		NetRestartWrap = 0;
+		if (NetDevExists) {
+			NetSetTimeout(10000UL, startAgainTimeout);
+			net_set_udp_handler(NULL);
+		} else {
+			net_set_state(NETLOOP_FAIL);
+		}
+	} else {
+		net_set_state(NETLOOP_RESTART);
+	}
+}
+
+/**********************************************************************/
+/*
+ *	Miscelaneous bits.
+ */
+
+static void dummy_handler(uchar *pkt, unsigned dport,
+			IPaddr_t sip, unsigned sport,
+			unsigned len)
+{
+}
+
+rxhand_f *net_get_udp_handler(void)
+{
+	return udp_packet_handler;
+}
+
+void net_set_udp_handler(rxhand_f *f)
+{
+	debug_cond(DEBUG_INT_STATE, "--- NetLoop 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, "--- NetLoop 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
+NetSetTimeout(ulong iv, thand_f *f)
+{
+	if (iv == 0) {
+		debug_cond(DEBUG_INT_STATE,
+			"--- NetLoop timeout handler cancelled\n");
+		timeHandler = (thand_f *)0;
+	} else {
+		debug_cond(DEBUG_INT_STATE,
+			"--- NetLoop timeout handler set (%p)\n", f);
+		timeHandler = f;
+		timeStart = get_timer(0);
+		timeDelta = iv * CONFIG_SYS_HZ / 1000;
+	}
+}
+
+int NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport,
+		int payload_len)
+{
+	uchar *pkt;
+	int eth_hdr_size;
+	int pkt_hdr_size;
+
+	/* make sure the NetTxPacket is initialized (NetInit() was called) */
+	assert(NetTxPacket != NULL);
+	if (NetTxPacket == NULL)
+		return -1;
+
+	/* convert to new style broadcast */
+	if (dest == 0)
+		dest = 0xFFFFFFFF;
+
+	/* if broadcast, make the ether address a broadcast and don't do ARP */
+	if (dest == 0xFFFFFFFF)
+		ether = NetBcastAddr;
+
+	pkt = (uchar *)NetTxPacket;
+
+	eth_hdr_size = NetSetEther(pkt, ether, PROT_IP);
+	pkt += eth_hdr_size;
+	net_set_udp_header(pkt, dest, dport, sport, payload_len);
+	pkt_hdr_size = eth_hdr_size + IP_UDP_HDR_SIZE;
+
+	/* if MAC address was not discovered yet, do an ARP request */
+	if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
+		//debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4\n", &dest);
+		printf("sending ARP for %pI4\n", &dest);
+
+		/* save the ip and eth addr for the packet to send after arp */
+		NetArpWaitPacketIP = dest;
+		NetArpWaitPacketMAC = ether;
+
+		/* size of the waiting packet */
+		NetArpWaitTxPacketSize = pkt_hdr_size + payload_len;
+
+		/* and do the ARP request */
+		NetArpWaitTry = 1;
+		NetArpWaitTimerStart = get_timer(0);
+		ArpRequest();
+		     
+		return 1;	/* waiting */
+    }else {
+		debug_cond(DEBUG_DEV_PKT, "sending UDP to %pI4/%pM\n",
+			&dest, ether);
+		NetSendPacket(NetTxPacket, pkt_hdr_size + payload_len);
+		return 0;	/* transmitted */
+	}
+}
+
+#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
+/*
+ * MAXDEFRAG, above, is chosen in the config file and  is real data
+ * so we need to add the NFS overhead, which is more than TFTP.
+ * To use sizeof in the internal unnamed structures, we need a real
+ * instance (can't do "sizeof(struct rpc_t.u.reply))", unfortunately).
+ * The compiler doesn't complain nor allocates the actual structure
+ */
+static struct rpc_t rpc_specimen;
+#define IP_PKTSIZE (CONFIG_NET_MAXDEFRAG + sizeof(rpc_specimen.u.reply))
+
+#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 *__NetDefragment(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 *NetDefragment(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 __NetDefragment(ip, lenp);
+}
+
+#else /* !CONFIG_IP_DEFRAG */
+
+static inline struct ip_udp_hdr *NetDefragment(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,
+			IPaddr_t 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
+NetReceive(uchar *inpkt, int len)
+{
+	struct ethernet_hdr *et;
+	struct ip_udp_hdr *ip;
+	IPaddr_t dst_ip;
+	IPaddr_t 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");
+	//printf("packet received \n");
+	NetRxPacket = inpkt;
+	NetRxPacketLen = len;
+	et = (struct ethernet_hdr *)inpkt;
+
+	/* too small packet? */
+	if (len < ETHER_HDR_SIZE)
+		return;
+
+#ifdef CONFIG_API
+	if (push_packet)
+	{
+		(*push_packet)(inpkt, len);
+		return;
+	}
+#endif
+
+#if defined(CONFIG_CMD_CDP)
+	/* keep track if packet is CDP */
+	iscdp = is_cdp_packet(et->et_dest);
+#endif
+
+	myvlanid = ntohs(NetOurVLAN);
+	if (myvlanid == (ushort)-1)
+		myvlanid = VLAN_NONE;
+	mynvlanid = ntohs(NetOurNativeVLAN);
+	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 *)(inpkt + E802_HDR_SIZE);
+		len -= E802_HDR_SIZE;
+
+	} 
+	else if (eth_proto != PROT_VLAN) 
+	{	/* normal packet */
+		ip = (struct ip_udp_hdr *)(inpkt + 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(NetOurVLAN) & 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 *)(inpkt + 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:
+		ArpReceive(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 (!NetCksumOk((uchar *)ip, IP_HDR_SIZE / 2)) 
+		{
+			debug("checksum bad\n");
+			return;
+		}
+		/* If it is not for us, ignore it */
+		dst_ip = NetReadIP(&ip->ip_dst);
+		if (NetOurIP && dst_ip != NetOurIP && dst_ip != 0xFFFFFFFF) {
+#ifdef CONFIG_MCAST_TFTP
+			if (Mcast_addr != dst_ip)
+#endif
+				return;
+		}
+		/* Read source IP address for later use */
+		src_ip = NetReadIP(&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 = NetDefragment(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
+		 * (wd@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 <sjg@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 */
+			return;
+		}
+
+		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) >> 16) & 0x0000ffff;
+			xsum += (ntohl(ip->ip_src) >>  0) & 0x0000ffff;
+			xsum += (ntohl(ip->ip_dst) >> 16) & 0x0000ffff;
+			xsum += (ntohl(ip->ip_dst) >>  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
+
+
+#ifdef CONFIG_NETCONSOLE
+		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.
+		 */
+		(*udp_packet_handler)((uchar *)ip + IP_UDP_HDR_SIZE,
+				ntohs(ip->udp_dst),
+				src_ip,
+				ntohs(ip->udp_src),
+				ntohs(ip->udp_len) - UDP_HDR_SIZE);
+		break;
+	}
+}
+
+
+/**********************************************************************/
+
+static int net_check_prereq(enum proto_t protocol)
+{
+	switch (protocol) {
+		/* Fall through */
+#if defined(CONFIG_CMD_PING)
+	case PING:
+		if (NetPingIP == 0) {
+			puts("*** ERROR: ping address not given\n");
+			return 1;
+		}
+		goto common;
+#endif
+#if defined(CONFIG_CMD_SNTP)
+	case SNTP:
+		if (NetNtpServerIP == 0) {
+			puts("*** ERROR: NTP server address not given\n");
+			return 1;
+		}
+		goto common;
+#endif
+#if defined(CONFIG_CMD_DNS)
+	case DNS:
+		if (NetOurDNSIP == 0) {
+			puts("*** ERROR: DNS server address not given\n");
+			return 1;
+		}
+		goto common;
+#endif
+#if defined(CONFIG_CMD_NFS)
+	case NFS:
+#endif
+	case TFTPGET:
+	case TFTPPUT:
+		if (NetServerIP == 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 (NetOurIP == 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(NetOurEther, "\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;
+			}
+
+			NetStartAgain();
+			return 2;
+		}
+		/* Fall through */
+	default:
+		return 0;
+	}
+	return 0;		/* OK */
+}
+/**********************************************************************/
+
+int
+NetCksumOk(uchar *ptr, int len)
+{
+	return !((NetCksum(ptr, len) + 1) & 0xfffe);
+}
+
+
+unsigned
+NetCksum(uchar *ptr, int len)
+{
+	ulong	xsum;
+	ushort *p = (ushort *)ptr;
+
+	xsum = 0;
+	while (len-- > 0)
+		xsum += *p++;
+	xsum = (xsum & 0xffff) + (xsum >> 16);
+	xsum = (xsum & 0xffff) + (xsum >> 16);
+	return xsum & 0xffff;
+}
+
+int
+NetEthHdrSize(void)
+{
+	ushort myvlanid;
+
+	myvlanid = ntohs(NetOurVLAN);
+	if (myvlanid == (ushort)-1)
+		myvlanid = VLAN_NONE;
+
+	return ((myvlanid & VLAN_IDMASK) == VLAN_NONE) ? ETHER_HDR_SIZE :
+		VLAN_ETHER_HDR_SIZE;
+}
+
+int
+NetSetEther(uchar *xet, uchar * addr, uint prot)
+{
+	struct ethernet_hdr *et = (struct ethernet_hdr *)xet;
+	ushort myvlanid;
+
+	myvlanid = ntohs(NetOurVLAN);
+	if (myvlanid == (ushort)-1)
+		myvlanid = VLAN_NONE;
+
+	memcpy(et->et_dest, addr, 6);
+	memcpy(et->et_src, NetOurEther, 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, NetOurEther, 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, IPaddr_t dest, IPaddr_t source)
+{
+	struct ip_udp_hdr *ip = (struct ip_udp_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(IP_HDR_SIZE);
+	ip->ip_id    = htons(NetIPID++);
+	ip->ip_off   = htons(IP_FLAGS_DFRAG);	/* Don't fragment */
+	ip->ip_ttl   = 255;
+	ip->ip_sum   = 0;
+	/* already in network byte order */
+	NetCopyIP((void *)&ip->ip_src, &source);
+	/* already in network byte order */
+	NetCopyIP((void *)&ip->ip_dst, &dest);
+}
+
+void net_set_udp_header(uchar *pkt, IPaddr_t 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, NetOurIP);
+	ip->ip_len   = htons(IP_UDP_HDR_SIZE + len);
+	ip->ip_p     = IPPROTO_UDP;
+	ip->ip_sum   = ~(NetCksum((uchar *)ip, IP_HDR_SIZE >> 1));
+
+	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)
+/*
+ * 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(IPaddr_t x, char *s)
+{
+	x = ntohl(x);
+	sprintf(s, "%d.%d.%d.%d",
+		(int) ((x >> 24) & 0xff),
+		(int) ((x >> 16) & 0xff),
+		(int) ((x >> 8) & 0xff), (int) ((x >> 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));
+}
diff --git a/boot/common/src/uboot/net/net_rand.h b/boot/common/src/uboot/net/net_rand.h
new file mode 100644
index 0000000..ba9d064
--- /dev/null
+++ b/boot/common/src/uboot/net/net_rand.h
@@ -0,0 +1,43 @@
+/*
+ *	Copied from LiMon - BOOTP.
+ *
+ *	Copyright 1994, 1995, 2000 Neil Russell.
+ *	(See License)
+ *	Copyright 2000 Paolo Scaffardi
+ */
+
+#ifndef __NET_RAND_H__
+#define __NET_RAND_H__
+
+#include <common.h>
+
+/*
+ * Return a seed for the PRNG derived from the eth0 MAC address.
+ */
+static inline unsigned int seed_mac(void)
+{
+	unsigned char enetaddr[6];
+	unsigned int seed;
+
+	/* get our mac */
+	eth_getenv_enetaddr("ethaddr", enetaddr);
+
+	seed = enetaddr[5];
+	seed ^= enetaddr[4] << 8;
+	seed ^= enetaddr[3] << 16;
+	seed ^= enetaddr[2] << 24;
+	seed ^= enetaddr[1];
+	seed ^= enetaddr[0] << 8;
+
+	return seed;
+}
+
+/*
+ * Seed the random number generator using the eth0 MAC address.
+ */
+static inline void srand_mac(void)
+{
+	srand(seed_mac());
+}
+
+#endif /* __NET_RAND_H__ */
diff --git a/boot/common/src/uboot/net/nfs.c b/boot/common/src/uboot/net/nfs.c
new file mode 100644
index 0000000..7f2393f
--- /dev/null
+++ b/boot/common/src/uboot/net/nfs.c
@@ -0,0 +1,755 @@
+/*
+ * NFS support driver - based on etherboot and U-BOOT's tftp.c
+ *
+ * Masami Komiya <mkomiya@sonare.it> 2004
+ *
+ */
+
+/* NOTE: the NFS code is heavily inspired by the NetBSD netboot code (read:
+ * large portions are copied verbatim) as distributed in OSKit 0.97.  A few
+ * changes were necessary to adapt the code to Etherboot and to fix several
+ * inconsistencies.  Also the RPC message preparation is done "by hand" to
+ * avoid adding netsprintf() which I find hard to understand and use.  */
+
+/* NOTE 2: Etherboot does not care about things beyond the kernel image, so
+ * it loads the kernel image off the boot server (ARP_SERVER) and does not
+ * access the client root disk (root-path in dhcpd.conf), which would use
+ * ARP_ROOTSERVER.  The root disk is something the operating system we are
+ * about to load needs to use.	This is different from the OSKit 0.97 logic.  */
+
+/* NOTE 3: Symlink handling introduced by Anselm M Hoffmeister, 2003-July-14
+ * If a symlink is encountered, it is followed as far as possible (recursion
+ * possible, maximum 16 steps). There is no clearing of ".."'s inside the
+ * path, so please DON'T DO THAT. thx. */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <malloc.h>
+#include "nfs.h"
+#include "bootp.h"
+
+#define HASHES_PER_LINE 65	/* Number of "loading" hashes per line	*/
+#define NFS_RETRY_COUNT 30
+#ifndef CONFIG_NFS_TIMEOUT
+# define NFS_TIMEOUT 2000UL
+#else
+# define NFS_TIMEOUT CONFIG_NFS_TIMEOUT
+#endif
+
+static int fs_mounted;
+static unsigned long rpc_id;
+static int nfs_offset = -1;
+static int nfs_len;
+
+static char dirfh[NFS_FHSIZE];	/* file handle of directory */
+static char filefh[NFS_FHSIZE]; /* file handle of kernel image */
+
+static enum net_loop_state nfs_download_state;
+static IPaddr_t NfsServerIP;
+static int	NfsSrvMountPort;
+static int	NfsSrvNfsPort;
+static int	NfsOurPort;
+static int	NfsTimeoutCount;
+static int	NfsState;
+#define STATE_PRCLOOKUP_PROG_MOUNT_REQ	1
+#define STATE_PRCLOOKUP_PROG_NFS_REQ	2
+#define STATE_MOUNT_REQ			3
+#define STATE_UMOUNT_REQ		4
+#define STATE_LOOKUP_REQ		5
+#define STATE_READ_REQ			6
+#define STATE_READLINK_REQ		7
+
+static char default_filename[64];
+static char *nfs_filename;
+static char *nfs_path;
+static char nfs_path_buff[2048];
+
+static inline int
+store_block(uchar *src, unsigned offset, unsigned len)
+{
+	ulong newsize = offset + len;
+#ifdef CONFIG_SYS_DIRECT_FLASH_NFS
+	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 */
+	{
+		(void)memcpy((void *)(load_addr + offset), src, len);
+	}
+
+	if (NetBootFileXferSize < (offset+len))
+		NetBootFileXferSize = newsize;
+	return 0;
+}
+
+static char*
+basename(char *path)
+{
+	char *fname;
+
+	fname = path + strlen(path) - 1;
+	while (fname >= path) {
+		if (*fname == '/') {
+			fname++;
+			break;
+		}
+		fname--;
+	}
+	return fname;
+}
+
+static char*
+dirname(char *path)
+{
+	char *fname;
+
+	fname = basename(path);
+	--fname;
+	*fname = '\0';
+	return path;
+}
+
+/**************************************************************************
+RPC_ADD_CREDENTIALS - Add RPC authentication/verifier entries
+**************************************************************************/
+static long *rpc_add_credentials(long *p)
+{
+	int hl;
+	int hostnamelen;
+	char hostname[256];
+
+	strcpy(hostname, "");
+	hostnamelen = strlen(hostname);
+
+	/* Here's the executive summary on authentication requirements of the
+	 * various NFS server implementations:	Linux accepts both AUTH_NONE
+	 * and AUTH_UNIX authentication (also accepts an empty hostname field
+	 * in the AUTH_UNIX scheme).  *BSD refuses AUTH_NONE, but accepts
+	 * AUTH_UNIX (also accepts an empty hostname field in the AUTH_UNIX
+	 * scheme).  To be safe, use AUTH_UNIX and pass the hostname if we have
+	 * it (if the BOOTP/DHCP reply didn't give one, just use an empty
+	 * hostname).  */
+
+	hl = (hostnamelen + 3) & ~3;
+
+	/* Provide an AUTH_UNIX credential.  */
+	*p++ = htonl(1);		/* AUTH_UNIX */
+	*p++ = htonl(hl+20);		/* auth length */
+	*p++ = htonl(0);		/* stamp */
+	*p++ = htonl(hostnamelen);	/* hostname string */
+	if (hostnamelen & 3)
+		*(p + hostnamelen / 4) = 0; /* add zero padding */
+	memcpy(p, hostname, hostnamelen);
+	p += hl / 4;
+	*p++ = 0;			/* uid */
+	*p++ = 0;			/* gid */
+	*p++ = 0;			/* auxiliary gid list */
+
+	/* Provide an AUTH_NONE verifier.  */
+	*p++ = 0;			/* AUTH_NONE */
+	*p++ = 0;			/* auth length */
+
+	return p;
+}
+
+/**************************************************************************
+RPC_LOOKUP - Lookup RPC Port numbers
+**************************************************************************/
+static void
+rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen)
+{
+	struct rpc_t pkt;
+	unsigned long id;
+	uint32_t *p;
+	int pktlen;
+	int sport;
+
+	id = ++rpc_id;
+	pkt.u.call.id = htonl(id);
+	pkt.u.call.type = htonl(MSG_CALL);
+	pkt.u.call.rpcvers = htonl(2);	/* use RPC version 2 */
+	pkt.u.call.prog = htonl(rpc_prog);
+	pkt.u.call.vers = htonl(2);	/* portmapper is version 2 */
+	pkt.u.call.proc = htonl(rpc_proc);
+	p = (uint32_t *)&(pkt.u.call.data);
+
+	if (datalen)
+		memcpy((char *)p, (char *)data, datalen*sizeof(uint32_t));
+
+	pktlen = (char *)p + datalen*sizeof(uint32_t) - (char *)&pkt;
+
+	memcpy((char *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE,
+		(char *)&pkt, pktlen);
+
+	if (rpc_prog == PROG_PORTMAP)
+		sport = SUNRPC_PORT;
+	else if (rpc_prog == PROG_MOUNT)
+		sport = NfsSrvMountPort;
+	else
+		sport = NfsSrvNfsPort;
+
+	NetSendUDPPacket(NetServerEther, NfsServerIP, sport, NfsOurPort,
+		pktlen);
+}
+
+/**************************************************************************
+RPC_LOOKUP - Lookup RPC Port numbers
+**************************************************************************/
+static void
+rpc_lookup_req(int prog, int ver)
+{
+	uint32_t data[16];
+
+	data[0] = 0; data[1] = 0;	/* auth credential */
+	data[2] = 0; data[3] = 0;	/* auth verifier */
+	data[4] = htonl(prog);
+	data[5] = htonl(ver);
+	data[6] = htonl(17);	/* IP_UDP */
+	data[7] = 0;
+
+	rpc_req(PROG_PORTMAP, PORTMAP_GETPORT, data, 8);
+}
+
+/**************************************************************************
+NFS_MOUNT - Mount an NFS Filesystem
+**************************************************************************/
+static void
+nfs_mount_req(char *path)
+{
+	uint32_t data[1024];
+	uint32_t *p;
+	int len;
+	int pathlen;
+
+	pathlen = strlen(path);
+
+	p = &(data[0]);
+	p = (uint32_t *)rpc_add_credentials((long *)p);
+
+	*p++ = htonl(pathlen);
+	if (pathlen & 3)
+		*(p + pathlen / 4) = 0;
+	memcpy(p, path, pathlen);
+	p += (pathlen + 3) / 4;
+
+	len = (uint32_t *)p - (uint32_t *)&(data[0]);
+
+	rpc_req(PROG_MOUNT, MOUNT_ADDENTRY, data, len);
+}
+
+/**************************************************************************
+NFS_UMOUNTALL - Unmount all our NFS Filesystems on the Server
+**************************************************************************/
+static void
+nfs_umountall_req(void)
+{
+	uint32_t data[1024];
+	uint32_t *p;
+	int len;
+
+	if ((NfsSrvMountPort == -1) || (!fs_mounted))
+		/* Nothing mounted, nothing to umount */
+		return;
+
+	p = &(data[0]);
+	p = (uint32_t *)rpc_add_credentials((long *)p);
+
+	len = (uint32_t *)p - (uint32_t *)&(data[0]);
+
+	rpc_req(PROG_MOUNT, MOUNT_UMOUNTALL, data, len);
+}
+
+/***************************************************************************
+ * NFS_READLINK (AH 2003-07-14)
+ * This procedure is called when read of the first block fails -
+ * this probably happens when it's a directory or a symlink
+ * In case of successful readlink(), the dirname is manipulated,
+ * so that inside the nfs() function a recursion can be done.
+ **************************************************************************/
+static void
+nfs_readlink_req(void)
+{
+	uint32_t data[1024];
+	uint32_t *p;
+	int len;
+
+	p = &(data[0]);
+	p = (uint32_t *)rpc_add_credentials((long *)p);
+
+	memcpy(p, filefh, NFS_FHSIZE);
+	p += (NFS_FHSIZE / 4);
+
+	len = (uint32_t *)p - (uint32_t *)&(data[0]);
+
+	rpc_req(PROG_NFS, NFS_READLINK, data, len);
+}
+
+/**************************************************************************
+NFS_LOOKUP - Lookup Pathname
+**************************************************************************/
+static void
+nfs_lookup_req(char *fname)
+{
+	uint32_t data[1024];
+	uint32_t *p;
+	int len;
+	int fnamelen;
+
+	fnamelen = strlen(fname);
+
+	p = &(data[0]);
+	p = (uint32_t *)rpc_add_credentials((long *)p);
+
+	memcpy(p, dirfh, NFS_FHSIZE);
+	p += (NFS_FHSIZE / 4);
+	*p++ = htonl(fnamelen);
+	if (fnamelen & 3)
+		*(p + fnamelen / 4) = 0;
+	memcpy(p, fname, fnamelen);
+	p += (fnamelen + 3) / 4;
+
+	len = (uint32_t *)p - (uint32_t *)&(data[0]);
+
+	rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
+}
+
+/**************************************************************************
+NFS_READ - Read File on NFS Server
+**************************************************************************/
+static void
+nfs_read_req(int offset, int readlen)
+{
+	uint32_t data[1024];
+	uint32_t *p;
+	int len;
+
+	p = &(data[0]);
+	p = (uint32_t *)rpc_add_credentials((long *)p);
+
+	memcpy(p, filefh, NFS_FHSIZE);
+	p += (NFS_FHSIZE / 4);
+	*p++ = htonl(offset);
+	*p++ = htonl(readlen);
+	*p++ = 0;
+
+	len = (uint32_t *)p - (uint32_t *)&(data[0]);
+
+	rpc_req(PROG_NFS, NFS_READ, data, len);
+}
+
+/**************************************************************************
+RPC request dispatcher
+**************************************************************************/
+
+static void
+NfsSend(void)
+{
+	debug("%s\n", __func__);
+
+	switch (NfsState) {
+	case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
+		rpc_lookup_req(PROG_MOUNT, 1);
+		break;
+	case STATE_PRCLOOKUP_PROG_NFS_REQ:
+		rpc_lookup_req(PROG_NFS, 2);
+		break;
+	case STATE_MOUNT_REQ:
+		nfs_mount_req(nfs_path);
+		break;
+	case STATE_UMOUNT_REQ:
+		nfs_umountall_req();
+		break;
+	case STATE_LOOKUP_REQ:
+		nfs_lookup_req(nfs_filename);
+		break;
+	case STATE_READ_REQ:
+		nfs_read_req(nfs_offset, nfs_len);
+		break;
+	case STATE_READLINK_REQ:
+		nfs_readlink_req();
+		break;
+	}
+}
+
+/**************************************************************************
+Handlers for the reply from server
+**************************************************************************/
+
+static int
+rpc_lookup_reply(int prog, uchar *pkt, unsigned len)
+{
+	struct rpc_t rpc_pkt;
+
+	memcpy((unsigned char *)&rpc_pkt, pkt, len);
+
+	debug("%s\n", __func__);
+
+	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
+		return -1;
+
+	if (rpc_pkt.u.reply.rstatus  ||
+	    rpc_pkt.u.reply.verifier ||
+	    rpc_pkt.u.reply.astatus)
+		return -1;
+
+	switch (prog) {
+	case PROG_MOUNT:
+		NfsSrvMountPort = ntohl(rpc_pkt.u.reply.data[0]);
+		break;
+	case PROG_NFS:
+		NfsSrvNfsPort = ntohl(rpc_pkt.u.reply.data[0]);
+		break;
+	}
+
+	return 0;
+}
+
+static int
+nfs_mount_reply(uchar *pkt, unsigned len)
+{
+	struct rpc_t rpc_pkt;
+
+	debug("%s\n", __func__);
+
+	memcpy((unsigned char *)&rpc_pkt, pkt, len);
+
+	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
+		return -1;
+
+	if (rpc_pkt.u.reply.rstatus  ||
+	    rpc_pkt.u.reply.verifier ||
+	    rpc_pkt.u.reply.astatus  ||
+	    rpc_pkt.u.reply.data[0])
+		return -1;
+
+	fs_mounted = 1;
+	memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+
+	return 0;
+}
+
+static int
+nfs_umountall_reply(uchar *pkt, unsigned len)
+{
+	struct rpc_t rpc_pkt;
+
+	debug("%s\n", __func__);
+
+	memcpy((unsigned char *)&rpc_pkt, pkt, len);
+
+	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
+		return -1;
+
+	if (rpc_pkt.u.reply.rstatus  ||
+	    rpc_pkt.u.reply.verifier ||
+	    rpc_pkt.u.reply.astatus)
+		return -1;
+
+	fs_mounted = 0;
+	memset(dirfh, 0, sizeof(dirfh));
+
+	return 0;
+}
+
+static int
+nfs_lookup_reply(uchar *pkt, unsigned len)
+{
+	struct rpc_t rpc_pkt;
+
+	debug("%s\n", __func__);
+
+	memcpy((unsigned char *)&rpc_pkt, pkt, len);
+
+	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
+		return -1;
+
+	if (rpc_pkt.u.reply.rstatus  ||
+	    rpc_pkt.u.reply.verifier ||
+	    rpc_pkt.u.reply.astatus  ||
+	    rpc_pkt.u.reply.data[0])
+		return -1;
+
+	memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+
+	return 0;
+}
+
+static int
+nfs_readlink_reply(uchar *pkt, unsigned len)
+{
+	struct rpc_t rpc_pkt;
+	int rlen;
+
+	debug("%s\n", __func__);
+
+	memcpy((unsigned char *)&rpc_pkt, pkt, len);
+
+	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
+		return -1;
+
+	if (rpc_pkt.u.reply.rstatus  ||
+	    rpc_pkt.u.reply.verifier ||
+	    rpc_pkt.u.reply.astatus  ||
+	    rpc_pkt.u.reply.data[0])
+		return -1;
+
+	rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */
+
+	if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') {
+		int pathlen;
+		strcat(nfs_path, "/");
+		pathlen = strlen(nfs_path);
+		memcpy(nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2]),
+			rlen);
+		nfs_path[pathlen + rlen] = 0;
+	} else {
+		memcpy(nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen);
+		nfs_path[rlen] = 0;
+	}
+	return 0;
+}
+
+static int
+nfs_read_reply(uchar *pkt, unsigned len)
+{
+	struct rpc_t rpc_pkt;
+	int rlen;
+
+	debug("%s\n", __func__);
+
+	memcpy((uchar *)&rpc_pkt, pkt, sizeof(rpc_pkt.u.reply));
+
+	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
+		return -1;
+
+	if (rpc_pkt.u.reply.rstatus  ||
+	    rpc_pkt.u.reply.verifier ||
+	    rpc_pkt.u.reply.astatus  ||
+	    rpc_pkt.u.reply.data[0]) {
+		if (rpc_pkt.u.reply.rstatus)
+			return -9999;
+		if (rpc_pkt.u.reply.astatus)
+			return -9999;
+		return -ntohl(rpc_pkt.u.reply.data[0]);
+	}
+
+	if ((nfs_offset != 0) && !((nfs_offset) %
+			(NFS_READ_SIZE / 2 * 10 * HASHES_PER_LINE)))
+		puts("\n\t ");
+	if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10)))
+		putc('#');
+
+	rlen = ntohl(rpc_pkt.u.reply.data[18]);
+	if (store_block((uchar *)pkt + sizeof(rpc_pkt.u.reply),
+			nfs_offset, rlen))
+		return -9999;
+
+	return rlen;
+}
+
+/**************************************************************************
+Interfaces of U-BOOT
+**************************************************************************/
+
+static void
+NfsTimeout(void)
+{
+	if (++NfsTimeoutCount > NFS_RETRY_COUNT) {
+		puts("\nRetry count exceeded; starting again\n");
+		NetStartAgain();
+	} else {
+		puts("T ");
+		NetSetTimeout(NFS_TIMEOUT, NfsTimeout);
+		NfsSend();
+	}
+}
+
+static void
+NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
+{
+	int rlen;
+
+	debug("%s\n", __func__);
+
+	if (dest != NfsOurPort)
+		return;
+
+	switch (NfsState) {
+	case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
+		rpc_lookup_reply(PROG_MOUNT, pkt, len);
+		NfsState = STATE_PRCLOOKUP_PROG_NFS_REQ;
+		NfsSend();
+		break;
+
+	case STATE_PRCLOOKUP_PROG_NFS_REQ:
+		rpc_lookup_reply(PROG_NFS, pkt, len);
+		NfsState = STATE_MOUNT_REQ;
+		NfsSend();
+		break;
+
+	case STATE_MOUNT_REQ:
+		if (nfs_mount_reply(pkt, len)) {
+			puts("*** ERROR: Cannot mount\n");
+			/* just to be sure... */
+			NfsState = STATE_UMOUNT_REQ;
+			NfsSend();
+		} else {
+			NfsState = STATE_LOOKUP_REQ;
+			NfsSend();
+		}
+		break;
+
+	case STATE_UMOUNT_REQ:
+		if (nfs_umountall_reply(pkt, len)) {
+			puts("*** ERROR: Cannot umount\n");
+			net_set_state(NETLOOP_FAIL);
+		} else {
+			puts("\ndone\n");
+			net_set_state(nfs_download_state);
+		}
+		break;
+
+	case STATE_LOOKUP_REQ:
+		if (nfs_lookup_reply(pkt, len)) {
+			puts("*** ERROR: File lookup fail\n");
+			NfsState = STATE_UMOUNT_REQ;
+			NfsSend();
+		} else {
+			NfsState = STATE_READ_REQ;
+			nfs_offset = 0;
+			nfs_len = NFS_READ_SIZE;
+			NfsSend();
+		}
+		break;
+
+	case STATE_READLINK_REQ:
+		if (nfs_readlink_reply(pkt, len)) {
+			puts("*** ERROR: Symlink fail\n");
+			NfsState = STATE_UMOUNT_REQ;
+			NfsSend();
+		} else {
+			debug("Symlink --> %s\n", nfs_path);
+			nfs_filename = basename(nfs_path);
+			nfs_path     = dirname(nfs_path);
+
+			NfsState = STATE_MOUNT_REQ;
+			NfsSend();
+		}
+		break;
+
+	case STATE_READ_REQ:
+		rlen = nfs_read_reply(pkt, len);
+		NetSetTimeout(NFS_TIMEOUT, NfsTimeout);
+		if (rlen > 0) {
+			nfs_offset += rlen;
+			NfsSend();
+		} else if ((rlen == -NFSERR_ISDIR) || (rlen == -NFSERR_INVAL)) {
+			/* symbolic link */
+			NfsState = STATE_READLINK_REQ;
+			NfsSend();
+		} else {
+			if (!rlen)
+				nfs_download_state = NETLOOP_SUCCESS;
+			NfsState = STATE_UMOUNT_REQ;
+			NfsSend();
+		}
+		break;
+	}
+}
+
+
+void
+NfsStart(void)
+{
+	debug("%s\n", __func__);
+	nfs_download_state = NETLOOP_FAIL;
+
+	NfsServerIP = NetServerIP;
+	nfs_path = (char *)nfs_path_buff;
+
+	if (nfs_path == NULL) {
+		net_set_state(NETLOOP_FAIL);
+		puts("*** ERROR: Fail allocate memory\n");
+		return;
+	}
+
+	if (BootFile[0] == '\0') {
+		sprintf(default_filename, "/nfsroot/%02X%02X%02X%02X.img",
+			NetOurIP & 0xFF,
+			(NetOurIP >>  8) & 0xFF,
+			(NetOurIP >> 16) & 0xFF,
+			(NetOurIP >> 24) & 0xFF);
+		strcpy(nfs_path, default_filename);
+
+		printf("*** Warning: no boot file name; using '%s'\n",
+			nfs_path);
+	} else {
+		char *p = BootFile;
+
+		p = strchr(p, ':');
+
+		if (p != NULL) {
+			NfsServerIP = string_to_ip(BootFile);
+			++p;
+			strcpy(nfs_path, p);
+		} else {
+			strcpy(nfs_path, BootFile);
+		}
+	}
+
+	nfs_filename = basename(nfs_path);
+	nfs_path     = dirname(nfs_path);
+
+	printf("Using %s device\n", eth_get_name());
+
+	printf("File transfer via NFS from server %pI4"
+		"; our IP address is %pI4", &NfsServerIP, &NetOurIP);
+
+	/* Check if we need to send across this subnet */
+	if (NetOurGatewayIP && NetOurSubnetMask) {
+		IPaddr_t OurNet	    = NetOurIP	  & NetOurSubnetMask;
+		IPaddr_t ServerNet  = NetServerIP & NetOurSubnetMask;
+
+		if (OurNet != ServerNet)
+			printf("; sending through gateway %pI4",
+				&NetOurGatewayIP);
+	}
+	printf("\nFilename '%s/%s'.", nfs_path, nfs_filename);
+
+	if (NetBootFileSize) {
+		printf(" Size is 0x%x Bytes = ", NetBootFileSize<<9);
+		print_size(NetBootFileSize<<9, "");
+	}
+	printf("\nLoad address: 0x%lx\n"
+		"Loading: *\b", load_addr);
+
+	NetSetTimeout(NFS_TIMEOUT, NfsTimeout);
+	net_set_udp_handler(NfsHandler);
+
+	NfsTimeoutCount = 0;
+	NfsState = STATE_PRCLOOKUP_PROG_MOUNT_REQ;
+
+	/*NfsOurPort = 4096 + (get_ticks() % 3072);*/
+	/*FIX ME !!!*/
+	NfsOurPort = 1000;
+
+	/* zero out server ether in case the server ip has changed */
+	memset(NetServerEther, 0, 6);
+
+	NfsSend();
+}
diff --git a/boot/common/src/uboot/net/nfs.h b/boot/common/src/uboot/net/nfs.h
new file mode 100644
index 0000000..a5a1b43
--- /dev/null
+++ b/boot/common/src/uboot/net/nfs.h
@@ -0,0 +1,80 @@
+/*
+ * (C) Masami Komiya <mkomiya@sonare.it> 2004
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+#ifndef __NFS_H__
+#define __NFS_H__
+
+#define SUNRPC_PORT     111
+
+#define PROG_PORTMAP    100000
+#define PROG_NFS        100003
+#define PROG_MOUNT      100005
+
+#define MSG_CALL        0
+#define MSG_REPLY       1
+
+#define PORTMAP_GETPORT 3
+
+#define MOUNT_ADDENTRY  1
+#define MOUNT_UMOUNTALL 4
+
+#define NFS_LOOKUP      4
+#define NFS_READLINK    5
+#define NFS_READ        6
+
+#define NFS_FHSIZE      32
+
+#define NFSERR_PERM     1
+#define NFSERR_NOENT    2
+#define NFSERR_ACCES    13
+#define NFSERR_ISDIR    21
+#define NFSERR_INVAL    22
+
+/* Block size used for NFS read accesses.  A RPC reply packet (including  all
+ * headers) must fit within a single Ethernet frame to avoid fragmentation.
+ * However, if CONFIG_IP_DEFRAG is set, the config file may want to use a
+ * bigger value. In any case, most NFS servers are optimized for a power of 2.
+ */
+#ifdef CONFIG_NFS_READ_SIZE
+#define NFS_READ_SIZE CONFIG_NFS_READ_SIZE
+#else
+#define NFS_READ_SIZE 1024 /* biggest power of two that fits Ether frame */
+#endif
+
+#define NFS_MAXLINKDEPTH 16
+
+struct rpc_t {
+	union {
+		uint8_t data[2048];
+		struct {
+			uint32_t id;
+			uint32_t type;
+			uint32_t rpcvers;
+			uint32_t prog;
+			uint32_t vers;
+			uint32_t proc;
+			uint32_t data[1];
+		} call;
+		struct {
+			uint32_t id;
+			uint32_t type;
+			uint32_t rstatus;
+			uint32_t verifier;
+			uint32_t v2;
+			uint32_t astatus;
+			uint32_t data[19];
+		} reply;
+	} u;
+};
+extern void NfsStart(void);	/* Begin NFS */
+
+
+/**********************************************************************/
+
+#endif /* __NFS_H__ */
diff --git a/boot/common/src/uboot/net/ping.c b/boot/common/src/uboot/net/ping.c
new file mode 100644
index 0000000..0710b92
--- /dev/null
+++ b/boot/common/src/uboot/net/ping.c
@@ -0,0 +1,115 @@
+/*
+ *	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, wd@denx.de
+ */
+
+#include "ping.h"
+#include "arp.h"
+
+static ushort PingSeqNo;
+
+/* The ip address to ping */
+IPaddr_t NetPingIP;
+
+static void set_icmp_header(uchar *pkt, IPaddr_t dest)
+{
+	/*
+	 *	Construct an IP and ICMP header.
+	 */
+	struct ip_hdr *ip = (struct ip_hdr *)pkt;
+	struct icmp_hdr *icmp = (struct icmp_hdr *)(pkt + IP_HDR_SIZE);
+
+	net_set_ip_header(pkt, dest, NetOurIP);
+
+	ip->ip_len   = htons(IP_ICMP_HDR_SIZE);
+	ip->ip_p     = IPPROTO_ICMP;
+	ip->ip_sum   = ~NetCksum((uchar *)ip, IP_HDR_SIZE >> 1);
+
+	icmp->type = ICMP_ECHO_REQUEST;
+	icmp->code = 0;
+	icmp->checksum = 0;
+	icmp->un.echo.id = 0;
+	icmp->un.echo.sequence = htons(PingSeqNo++);
+	icmp->checksum = ~NetCksum((uchar *)icmp, ICMP_HDR_SIZE	>> 1);
+}
+
+static int ping_send(void)
+{
+	uchar *pkt;
+	int eth_hdr_size;
+
+	/* XXX always send arp request */
+
+	debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4\n", &NetPingIP);
+
+	NetArpWaitPacketIP = NetPingIP;
+
+	eth_hdr_size = NetSetEther(NetTxPacket, NetEtherNullAddr, PROT_IP);
+	pkt = (uchar *)NetTxPacket + eth_hdr_size;
+
+	set_icmp_header(pkt, NetPingIP);
+
+	/* size of the waiting packet */
+	NetArpWaitTxPacketSize = eth_hdr_size + IP_ICMP_HDR_SIZE;
+
+	/* and do the ARP request */
+	NetArpWaitTry = 1;
+	NetArpWaitTimerStart = get_timer(0);
+	ArpRequest();
+	return 1;	/* waiting */
+}
+
+static void ping_timeout(void)
+{
+	eth_halt();
+	net_set_state(NETLOOP_FAIL);	/* we did not get the reply */
+}
+
+void ping_start(void)
+{
+	printf("Using %s device\n", eth_get_name());
+	NetSetTimeout(10000UL, ping_timeout);
+
+	ping_send();
+}
+
+void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len)
+{
+	struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src;
+	IPaddr_t src_ip;
+	int eth_hdr_size;
+
+	switch (icmph->type) {
+	case ICMP_ECHO_REPLY:
+		src_ip = NetReadIP((void *)&ip->ip_src);
+		if (src_ip == NetPingIP)
+			net_set_state(NETLOOP_SUCCESS);
+		return;
+	case ICMP_ECHO_REQUEST:
+		eth_hdr_size = net_update_ether(et, et->et_src, PROT_IP);
+
+		debug_cond(DEBUG_DEV_PKT, "Got ICMP ECHO REQUEST, return "
+			"%d bytes\n", eth_hdr_size + len);
+
+		ip->ip_sum = 0;
+		ip->ip_off = 0;
+		NetCopyIP((void *)&ip->ip_dst, &ip->ip_src);
+		NetCopyIP((void *)&ip->ip_src, &NetOurIP);
+		ip->ip_sum = ~NetCksum((uchar *)ip,
+				       IP_HDR_SIZE >> 1);
+
+		icmph->type = ICMP_ECHO_REPLY;
+		icmph->checksum = 0;
+		icmph->checksum = ~NetCksum((uchar *)icmph,
+			(len - IP_HDR_SIZE) >> 1);
+		NetSendPacket((uchar *)et, eth_hdr_size + len);
+		return;
+/*	default:
+		return;*/
+	}
+}
diff --git a/boot/common/src/uboot/net/ping.h b/boot/common/src/uboot/net/ping.h
new file mode 100644
index 0000000..8c71be4
--- /dev/null
+++ b/boot/common/src/uboot/net/ping.h
@@ -0,0 +1,31 @@
+/*
+ *	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, wd@denx.de
+ */
+
+#ifndef __PING_H__
+#define __PING_H__
+
+#include <common.h>
+#include <net.h>
+
+/*
+ * Initialize ping (beginning of netloop)
+ */
+void ping_start(void);
+
+/*
+ * Deal with the receipt of a ping packet
+ *
+ * @param et Ethernet header in packet
+ * @param ip IP header in the same packet
+ * @param len Packet length
+ */
+void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len);
+
+#endif /* __PING_H__ */
diff --git a/boot/common/src/uboot/net/rarp.c b/boot/common/src/uboot/net/rarp.c
new file mode 100644
index 0000000..49185b4
--- /dev/null
+++ b/boot/common/src/uboot/net/rarp.c
@@ -0,0 +1,116 @@
+/*
+ * (C) Copyright 2000-2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include "nfs.h"
+#include "bootp.h"
+#include "rarp.h"
+#include "tftp.h"
+
+#define TIMEOUT 5000UL /* Milliseconds before trying BOOTP again */
+#ifndef	CONFIG_NET_RETRY_COUNT
+#define TIMEOUT_COUNT 5 /* # of timeouts before giving up  */
+#else
+#define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT)
+#endif
+
+int RarpTry;
+
+/*
+ *	Handle a RARP received packet.
+ */
+void rarp_receive(struct ip_udp_hdr *ip, unsigned len)
+{
+	struct arp_hdr *arp;
+
+	debug_cond(DEBUG_NET_PKT, "Got RARP\n");
+	arp = (struct arp_hdr *)ip;
+	if (len < ARP_HDR_SIZE) {
+		printf("bad length %d < %d\n", len, ARP_HDR_SIZE);
+		return;
+	}
+
+	if ((ntohs(arp->ar_op) != RARPOP_REPLY) ||
+		(ntohs(arp->ar_hrd) != ARP_ETHER)   ||
+		(ntohs(arp->ar_pro) != PROT_IP)     ||
+		(arp->ar_hln != 6) || (arp->ar_pln != 4)) {
+
+		puts("invalid RARP header\n");
+	} else {
+		NetCopyIP(&NetOurIP, &arp->ar_data[16]);
+		if (NetServerIP == 0)
+			NetCopyIP(&NetServerIP, &arp->ar_data[6]);
+		memcpy(NetServerEther, &arp->ar_data[0], 6);
+		debug_cond(DEBUG_DEV_PKT, "Got good RARP\n");
+		net_auto_load();
+	}
+}
+
+
+/*
+ *	Timeout on BOOTP request.
+ */
+static void RarpTimeout(void)
+{
+	if (RarpTry >= TIMEOUT_COUNT) {
+		puts("\nRetry count exceeded; starting again\n");
+		NetStartAgain();
+	} else {
+		NetSetTimeout(TIMEOUT, RarpTimeout);
+		RarpRequest();
+	}
+}
+
+
+void RarpRequest(void)
+{
+	uchar *pkt;
+	struct arp_hdr *rarp;
+	int eth_hdr_size;
+
+	printf("RARP broadcast %d\n", ++RarpTry);
+	pkt = NetTxPacket;
+
+	eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_RARP);
+	pkt += eth_hdr_size;
+
+	rarp = (struct arp_hdr *)pkt;
+
+	rarp->ar_hrd = htons(ARP_ETHER);
+	rarp->ar_pro = htons(PROT_IP);
+	rarp->ar_hln = 6;
+	rarp->ar_pln = 4;
+	rarp->ar_op  = htons(RARPOP_REQUEST);
+	memcpy(&rarp->ar_data[0],  NetOurEther, 6);	/* source ET addr */
+	memcpy(&rarp->ar_data[6],  &NetOurIP,   4);	/* source IP addr */
+	/* dest ET addr = source ET addr ??*/
+	memcpy(&rarp->ar_data[10], NetOurEther, 6);
+	/* dest IP addr set to broadcast */
+	memset(&rarp->ar_data[16], 0xff,        4);
+
+	NetSendPacket(NetTxPacket, eth_hdr_size + ARP_HDR_SIZE);
+
+	NetSetTimeout(TIMEOUT, RarpTimeout);
+}
diff --git a/boot/common/src/uboot/net/rarp.h b/boot/common/src/uboot/net/rarp.h
new file mode 100644
index 0000000..ebd748e
--- /dev/null
+++ b/boot/common/src/uboot/net/rarp.h
@@ -0,0 +1,45 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#if defined(CONFIG_CMD_RARP)
+
+#ifndef __RARP_H__
+#define __RARP_H__
+
+#include <net.h>
+
+/**********************************************************************/
+/*
+ *	Global functions and variables.
+ */
+
+extern int RarpTry;
+
+/* Process the receipt of a RARP packet */
+extern void rarp_receive(struct ip_udp_hdr *ip, unsigned len);
+extern void RarpRequest(void);	/* Send a RARP request */
+
+/**********************************************************************/
+
+#endif /* __RARP_H__ */
+#endif
diff --git a/boot/common/src/uboot/net/sntp.c b/boot/common/src/uboot/net/sntp.c
new file mode 100644
index 0000000..5de1952
--- /dev/null
+++ b/boot/common/src/uboot/net/sntp.c
@@ -0,0 +1,92 @@
+/*
+ * SNTP support driver
+ *
+ * Masami Komiya <mkomiya@sonare.it> 2005
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <rtc.h>
+
+#include "sntp.h"
+
+#define SNTP_TIMEOUT 10000UL
+
+static int SntpOurPort;
+
+static void
+SntpSend(void)
+{
+	struct sntp_pkt_t pkt;
+	int pktlen = SNTP_PACKET_LEN;
+	int sport;
+
+	debug("%s\n", __func__);
+
+	memset(&pkt, 0, sizeof(pkt));
+
+	pkt.li = NTP_LI_NOLEAP;
+	pkt.vn = NTP_VERSION;
+	pkt.mode = NTP_MODE_CLIENT;
+
+	memcpy((char *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE,
+		(char *)&pkt, pktlen);
+
+	SntpOurPort = 10000 + (get_timer(0) % 4096);
+	sport = NTP_SERVICE_PORT;
+
+	NetSendUDPPacket(NetServerEther, NetNtpServerIP, sport, SntpOurPort,
+		pktlen);
+}
+
+static void
+SntpTimeout(void)
+{
+	puts("Timeout\n");
+	net_set_state(NETLOOP_FAIL);
+	return;
+}
+
+static void
+SntpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+	    unsigned len)
+{
+	struct sntp_pkt_t *rpktp = (struct sntp_pkt_t *)pkt;
+	struct rtc_time tm;
+	ulong seconds;
+
+	debug("%s\n", __func__);
+
+	if (dest != SntpOurPort)
+		return;
+
+	/*
+	 * As the RTC's used in U-Boot sepport second resolution only
+	 * we simply ignore the sub-second field.
+	 */
+	memcpy(&seconds, &rpktp->transmit_timestamp, sizeof(ulong));
+
+	to_tm(ntohl(seconds) - 2208988800UL + NetTimeOffset, &tm);
+#if defined(CONFIG_CMD_DATE)
+	rtc_set(&tm);
+#endif
+	printf("Date: %4d-%02d-%02d Time: %2d:%02d:%02d\n",
+		tm.tm_year, tm.tm_mon, tm.tm_mday,
+		tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+	net_set_state(NETLOOP_SUCCESS);
+}
+
+void
+SntpStart(void)
+{
+	debug("%s\n", __func__);
+
+	NetSetTimeout(SNTP_TIMEOUT, SntpTimeout);
+	net_set_udp_handler(SntpHandler);
+	memset(NetServerEther, 0, sizeof(NetServerEther));
+
+	SntpSend();
+}
diff --git a/boot/common/src/uboot/net/sntp.h b/boot/common/src/uboot/net/sntp.h
new file mode 100644
index 0000000..1d0046e
--- /dev/null
+++ b/boot/common/src/uboot/net/sntp.h
@@ -0,0 +1,61 @@
+/*
+ * (C) Masami Komiya <mkomiya@sonare.it> 2005
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ */
+
+#ifndef __SNTP_H__
+#define __SNTP_H__
+
+#define NTP_SERVICE_PORT	123
+#define SNTP_PACKET_LEN		48
+
+
+/* Leap Indicator */
+#define NTP_LI_NOLEAP		0x0
+#define NTP_LI_61SECS		0x1
+#define NTP_LI_59SECS		0x2
+#define NTP_LI_ALARM		0x3
+
+/* Version */
+
+#define NTP_VERSION		4
+
+/* Mode */
+#define NTP_MODE_RESERVED	0
+#define NTP_MODE_SYMACTIVE	1	/* Symmetric Active */
+#define NTP_MODE_SYMPASSIVE	2	/* Symmetric Passive */
+#define NTP_MODE_CLIENT		3
+#define NTP_MODE_SERVER		4
+#define NTP_MODE_BROADCAST	5
+#define NTP_MODE_NTPCTRL	6	/* Reserved for NTP control message */
+#define NTP_MODE_PRIVATE	7	/* Reserved for private use */
+
+struct sntp_pkt_t {
+#if __LITTLE_ENDIAN
+	uchar mode:3;
+	uchar vn:3;
+	uchar li:2;
+#else
+	uchar li:2;
+	uchar vn:3;
+	uchar mode:3;
+#endif
+	uchar stratum;
+	uchar poll;
+	uchar precision;
+	uint root_delay;
+	uint root_dispersion;
+	uint reference_id;
+	unsigned long long reference_timestamp;
+	unsigned long long originate_timestamp;
+	unsigned long long receive_timestamp;
+	unsigned long long transmit_timestamp;
+};
+
+extern void SntpStart(void);	/* Begin SNTP */
+
+#endif /* __SNTP_H__ */
diff --git a/boot/common/src/uboot/net/tftp.c b/boot/common/src/uboot/net/tftp.c
new file mode 100644
index 0000000..fe2f147
--- /dev/null
+++ b/boot/common/src/uboot/net/tftp.c
@@ -0,0 +1,957 @@
+/*
+ * Copyright 1994, 1995, 2000 Neil Russell.
+ * (See License)
+ * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
+ * Copyright 2011 Comelit Group SpA,
+ *                Luca Ceresoli <luca.ceresoli@comelit.it>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include "tftp.h"
+#include "bootp.h"
+#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP
+#include <flash.h>
+#endif
+extern uint32_t g_gmac_init_overtime;
+extern ulong  time_over;
+/* Well known TFTP port # */
+#define WELL_KNOWN_PORT	69
+/* Millisecs to timeout for lost pkt */
+#define TIMEOUT		5000UL
+
+#ifndef	CONFIG_NET_RETRY_COUNT
+/* # of timeouts before giving up */
+# define TIMEOUT_COUNT	10
+#else
+# define TIMEOUT_COUNT  (CONFIG_NET_RETRY_COUNT * 2)
+#endif
+/* Number of "loading" hashes per line (for checking the image size) */
+#define HASHES_PER_LINE	65
+
+/*
+ *	TFTP operations.
+ */
+#define TFTP_RRQ	1
+#define TFTP_WRQ	2
+#define TFTP_DATA	3
+#define TFTP_ACK	4
+#define TFTP_ERROR	5
+#define TFTP_OACK	6
+
+static ulong TftpTimeoutMSecs = TIMEOUT;
+static int TftpTimeoutCountMax = TIMEOUT_COUNT;
+static ulong time_start;   /* Record time we started tftp */
+
+/*
+ * These globals govern the timeout behavior when attempting a connection to a
+ * TFTP server. TftpRRQTimeoutMSecs specifies the number of milliseconds to
+ * wait for the server to respond to initial connection. Second global,
+ * TftpRRQTimeoutCountMax, gives the number of such connection retries.
+ * TftpRRQTimeoutCountMax must be non-negative and TftpRRQTimeoutMSecs must be
+ * positive. The globals are meant to be set (and restored) by code needing
+ * non-standard timeout behavior when initiating a TFTP transfer.
+ */
+ulong TftpRRQTimeoutMSecs = TIMEOUT;
+int TftpRRQTimeoutCountMax = TIMEOUT_COUNT;
+
+enum {
+	TFTP_ERR_UNDEFINED           = 0,
+	TFTP_ERR_FILE_NOT_FOUND      = 1,
+	TFTP_ERR_ACCESS_DENIED       = 2,
+	TFTP_ERR_DISK_FULL           = 3,
+	TFTP_ERR_UNEXPECTED_OPCODE   = 4,
+	TFTP_ERR_UNKNOWN_TRANSFER_ID  = 5,
+	TFTP_ERR_FILE_ALREADY_EXISTS = 6,
+};
+
+static IPaddr_t TftpRemoteIP;
+/* The UDP port at their end */
+static int	TftpRemotePort;
+/* The UDP port at our end */
+static int	TftpOurPort;
+static int	TftpTimeoutCount;
+/* packet sequence number */
+static ulong	TftpBlock;
+/* last packet sequence number received */
+static ulong	TftpLastBlock;
+/* count of sequence number wraparounds */
+static ulong	TftpBlockWrap;
+/* memory offset due to wrapping */
+static ulong	TftpBlockWrapOffset;
+static int	TftpState;
+#ifdef CONFIG_TFTP_TSIZE
+/* The file size reported by the server */
+static int	TftpTsize;
+/* The number of hashes we printed */
+static short	TftpNumchars;
+#endif
+#ifdef CONFIG_CMD_TFTPPUT
+static int	TftpWriting;	/* 1 if writing, else 0 */
+static int	TftpFinalBlock;	/* 1 if we have sent the last block */
+#else
+#define TftpWriting	0
+#endif
+
+#define STATE_SEND_RRQ	1
+#define STATE_DATA	2
+#define STATE_TOO_LARGE	3
+#define STATE_BAD_MAGIC	4
+#define STATE_OACK	5
+#define STATE_RECV_WRQ	6
+#define STATE_SEND_WRQ	7
+
+/* default TFTP block size */
+#define TFTP_BLOCK_SIZE		512
+/* sequence number is 16 bit */
+#define TFTP_SEQUENCE_SIZE	((ulong)(1<<16))
+
+#define DEFAULT_NAME_LEN	(8 + 4 + 1)
+static char default_filename[DEFAULT_NAME_LEN];
+
+#ifndef CONFIG_TFTP_FILE_NAME_MAX_LEN
+#define MAX_LEN 128
+#else
+#define MAX_LEN CONFIG_TFTP_FILE_NAME_MAX_LEN
+#endif
+
+static char tftp_filename[MAX_LEN];
+
+/* 512 is poor choice for ethernet, MTU is typically 1500.
+ * Minus eth.hdrs thats 1468.  Can get 2x better throughput with
+ * almost-MTU block sizes.  At least try... fall back to 512 if need be.
+ * (but those using CONFIG_IP_DEFRAG may want to set a larger block in cfg file)
+ */
+#ifdef CONFIG_TFTP_BLOCKSIZE
+#define TFTP_MTU_BLOCKSIZE CONFIG_TFTP_BLOCKSIZE
+#else
+#define TFTP_MTU_BLOCKSIZE 1468
+#endif
+
+static unsigned short TftpBlkSize = TFTP_BLOCK_SIZE;
+static unsigned short TftpBlkSizeOption = TFTP_MTU_BLOCKSIZE;
+int tftp_server_cnt = 0;
+
+#ifdef CONFIG_MCAST_TFTP
+#include <malloc.h>
+#define MTFTP_BITMAPSIZE	0x1000
+static unsigned *Bitmap;
+static int PrevBitmapHole, Mapsize = MTFTP_BITMAPSIZE;
+static uchar ProhibitMcast, MasterClient;
+static uchar Multicast;
+static int Mcast_port;
+static ulong TftpEndingBlock; /* can get 'last' block before done..*/
+
+static void parse_multicast_oack(char *pkt, int len);
+
+static void
+mcast_cleanup(void)
+{
+	if (Mcast_addr)
+		eth_mcast_join(Mcast_addr, 0);
+	if (Bitmap)
+		free(Bitmap);
+	Bitmap = NULL;
+	Mcast_addr = Multicast = Mcast_port = 0;
+	TftpEndingBlock = -1;
+}
+
+#endif	/* CONFIG_MCAST_TFTP */
+
+static inline void
+store_block(int block, uchar *src, unsigned len)
+{
+	ulong offset = block * TftpBlkSize + TftpBlockWrapOffset;
+	ulong newsize = offset + len;
+#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP
+	int i, rc = 0;
+
+	for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
+		/* start address in flash? */
+		if (flash_info[i].flash_id == FLASH_UNKNOWN)
+			continue;
+		if (load_addr + offset >= flash_info[i].start[0]) {
+			rc = 1;
+			break;
+		}
+	}
+
+	if (rc) { /* Flash is destination for this packet */
+		rc = flash_write((char *)src, (ulong)(load_addr+offset), len);
+		if (rc) {
+			flash_perror(rc);
+			net_set_state(NETLOOP_FAIL);
+			return;
+		}
+	} else
+#endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */
+	{
+		(void)memcpy((void *)(load_addr + offset), src, len);
+	}
+#ifdef CONFIG_MCAST_TFTP
+	if (Multicast)
+		ext2_set_bit(block, Bitmap);
+#endif
+
+	if (NetBootFileXferSize < newsize)
+		NetBootFileXferSize = newsize;
+}
+
+/* Clear our state ready for a new transfer */
+static void new_transfer(void)
+{
+	TftpLastBlock = 0;
+	TftpBlockWrap = 0;
+	TftpBlockWrapOffset = 0;
+#ifdef CONFIG_CMD_TFTPPUT
+	TftpFinalBlock = 0;
+#endif
+}
+
+#ifdef CONFIG_CMD_TFTPPUT
+/**
+ * Load the next block from memory to be sent over tftp.
+ *
+ * @param block	Block number to send
+ * @param dst	Destination buffer for data
+ * @param len	Number of bytes in block (this one and every other)
+ * @return number of bytes loaded
+ */
+static int load_block(unsigned block, uchar *dst, unsigned len)
+{
+	/* We may want to get the final block from the previous set */
+	ulong offset = ((int)block - 1) * len + TftpBlockWrapOffset;
+	ulong tosend = len;
+
+	tosend = min(NetBootFileXferSize - offset, tosend);
+	(void)memcpy(dst, (void *)(save_addr + offset), tosend);
+	debug("%s: block=%d, offset=%ld, len=%d, tosend=%ld\n", __func__,
+		block, offset, len, tosend);
+	return tosend;
+}
+#endif
+
+static int TftpSend(void);
+static int TftpTimeout(void);
+
+/**********************************************************************/
+
+static void show_block_marker(void)
+{
+#ifdef CONFIG_TFTP_TSIZE
+	if (TftpTsize) {
+		ulong pos = TftpBlock * TftpBlkSize + TftpBlockWrapOffset;
+
+		while (TftpNumchars < pos * 50 / TftpTsize) {
+			putc('#');
+			TftpNumchars++;
+		}
+	} else
+#endif
+	{
+		if (((TftpBlock - 1) % 10) == 0)
+			putc('#');
+		else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0)
+			puts("\n\t ");
+	}
+}
+
+/**
+ * restart the current transfer due to an error
+ *
+ * @param msg	Message to print for user
+ */
+static void restart(const char *msg)
+{
+	printf("\n%s; starting again\n", msg);
+#ifdef CONFIG_MCAST_TFTP
+	mcast_cleanup();
+#endif
+	NetStartAgain();
+}
+
+/*
+ * Check if the block number has wrapped, and update progress
+ *
+ * TODO: The egregious use of global variables in this file should be tidied.
+ */
+static void update_block_number(void)
+{
+	/*
+	 * RFC1350 specifies that the first data packet will
+	 * have sequence number 1. If we receive a sequence
+	 * number of 0 this means that there was a wrap
+	 * around of the (16 bit) counter.
+	 */
+	if (TftpBlock == 0) {
+		TftpBlockWrap++;
+		TftpBlockWrapOffset += TftpBlkSize * TFTP_SEQUENCE_SIZE;
+		TftpTimeoutCount = 0; /* we've done well, reset thhe timeout */
+	} else {
+		show_block_marker();
+	}
+}
+
+/* The TFTP get or put is complete */
+static void tftp_complete(void)
+{
+#ifdef CONFIG_TFTP_TSIZE
+	/* Print hash marks for the last packet received */
+	while (TftpTsize && TftpNumchars < 49) {
+		putc('#');
+		TftpNumchars++;
+	}
+#endif
+	time_start = get_timer(time_start);
+	if (time_start > 0) {
+		puts("\n\t ");	/* Line up with "Loading: " */
+		print_size(NetBootFileXferSize /
+			time_start * 1000, "/s");
+	}
+	puts("\ndone\n");
+	net_set_state(NETLOOP_SUCCESS);
+}
+
+static int
+TftpSend(void)
+{
+	uchar *pkt;
+	uchar *xp;
+	int len = 0;
+	ushort *s;
+
+#ifdef CONFIG_MCAST_TFTP
+	/* Multicast TFTP.. non-MasterClients do not ACK data. */
+	if (Multicast
+	 && (TftpState == STATE_DATA)
+	 && (MasterClient == 0))
+		return;
+#endif
+	/*
+	 *	We will always be sending some sort of packet, so
+	 *	cobble together the packet headers now.
+	 */
+	pkt = NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
+
+	switch (TftpState) {
+	case STATE_SEND_RRQ:
+	case STATE_SEND_WRQ:
+		xp = pkt;
+		s = (ushort *)pkt;
+#ifdef CONFIG_CMD_TFTPPUT
+		*s++ = htons(TftpState == STATE_SEND_RRQ ? TFTP_RRQ :
+			TFTP_WRQ);
+#else
+		*s++ = htons(TFTP_RRQ);
+#endif
+		pkt = (uchar *)s;
+		strcpy((char *)pkt, tftp_filename);
+		pkt += strlen(tftp_filename) + 1;
+		strcpy((char *)pkt, "octet");
+		pkt += 5 /*strlen("octet")*/ + 1;
+		strcpy((char *)pkt, "timeout");
+		pkt += 7 /*strlen("timeout")*/ + 1;
+		sprintf((char *)pkt, "%lu", TftpTimeoutMSecs / 1000);
+		debug("send option \"timeout %s\"\n", (char *)pkt);
+		pkt += strlen((char *)pkt) + 1;
+#ifdef CONFIG_TFTP_TSIZE
+		pkt += sprintf((char *)pkt, "tsize%c%lu%c",
+				0, NetBootFileXferSize, 0);
+#endif
+		/* try for more effic. blk size */
+		pkt += sprintf((char *)pkt, "blksize%c%d%c",
+				0, TftpBlkSizeOption, 0);
+#ifdef CONFIG_MCAST_TFTP
+		/* Check all preconditions before even trying the option */
+		if (!ProhibitMcast) {
+			Bitmap = malloc(Mapsize);
+			if (Bitmap && eth_get_dev()->mcast) {
+				free(Bitmap);
+				Bitmap = NULL;
+				pkt += sprintf((char *)pkt, "multicast%c%c",
+					0, 0);
+			}
+		}
+#endif /* CONFIG_MCAST_TFTP */
+		len = pkt - xp;
+		break;
+
+	case STATE_OACK:
+#ifdef CONFIG_MCAST_TFTP
+		/* My turn!  Start at where I need blocks I missed.*/
+		if (Multicast)
+			TftpBlock = ext2_find_next_zero_bit(Bitmap,
+							    (Mapsize*8), 0);
+		/*..falling..*/
+#endif
+
+	case STATE_RECV_WRQ:
+	case STATE_DATA:
+		xp = pkt;
+		s = (ushort *)pkt;
+		s[0] = htons(TFTP_ACK);
+		s[1] = htons(TftpBlock);
+		pkt = (uchar *)(s + 2);
+#ifdef CONFIG_CMD_TFTPPUT
+		if (TftpWriting) {
+			int toload = TftpBlkSize;
+			int loaded = load_block(TftpBlock, pkt, toload);
+
+			s[0] = htons(TFTP_DATA);
+			pkt += loaded;
+			TftpFinalBlock = (loaded < toload);
+		}
+#endif
+		len = pkt - xp;
+		break;
+
+	case STATE_TOO_LARGE:
+		xp = pkt;
+		s = (ushort *)pkt;
+		*s++ = htons(TFTP_ERROR);
+			*s++ = htons(3);
+
+		pkt = (uchar *)s;
+		strcpy((char *)pkt, "File too large");
+		pkt += 14 /*strlen("File too large")*/ + 1;
+		len = pkt - xp;
+		break;
+
+	case STATE_BAD_MAGIC:
+		xp = pkt;
+		s = (ushort *)pkt;
+		*s++ = htons(TFTP_ERROR);
+		*s++ = htons(2);
+		pkt = (uchar *)s;
+		strcpy((char *)pkt, "File has bad magic");
+		pkt += 18 /*strlen("File has bad magic")*/ + 1;
+		len = pkt - xp;
+		break;
+	}
+	NetSendUDPPacket(NetServerEther, TftpRemoteIP, TftpRemotePort,
+		 TftpOurPort, len);
+
+	return 0;
+}
+
+#ifdef CONFIG_CMD_TFTPPUT
+static void icmp_handler(unsigned type, unsigned code, unsigned dest,
+			 IPaddr_t sip, unsigned src, uchar *pkt, unsigned len)
+{
+	if (type == ICMP_NOT_REACH && code == ICMP_NOT_REACH_PORT) {
+		/* Oh dear the other end has gone away */
+		restart("TFTP server died");
+	}
+}
+#endif
+
+static void
+TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
+	    unsigned len)
+{
+	ushort proto;
+	ushort *s;
+	int i;
+
+	if (dest != TftpOurPort) {
+#ifdef CONFIG_MCAST_TFTP
+		if (Multicast
+		 && (!Mcast_port || (dest != Mcast_port)))
+#endif
+			return;
+	}
+	if (TftpState != STATE_SEND_RRQ && src != TftpRemotePort &&
+	    TftpState != STATE_RECV_WRQ && TftpState != STATE_SEND_WRQ)
+		return;
+
+	if (len < 2)
+		return;
+	len -= 2;
+	/* warning: don't use increment (++) in ntohs() macros!! */
+	s = (ushort *)pkt;
+	proto = *s++;
+	pkt = (uchar *)s;
+	switch (ntohs(proto)) {
+
+	case TFTP_RRQ:
+		break;
+
+	case TFTP_ACK:
+	
+#ifdef CONFIG_CMD_TFTPPUT
+    
+		if (TftpWriting) {
+			if (TftpFinalBlock) {
+				tftp_complete();
+			} else {
+				/*
+				 * Move to the next block. We want our block
+				 * count to wrap just like the other end!
+				 */
+				int block = ntohs(*s);
+				int ack_ok = (TftpBlock == block);
+
+				TftpBlock = (unsigned short)(block + 1);
+				update_block_number();
+				if (ack_ok)
+					TftpSend(); /* Send next data block */
+			}
+		}
+#endif
+		break;
+
+	default:
+		break;
+
+#ifdef CONFIG_CMD_TFTPSRV
+	case TFTP_WRQ:
+		debug("Got WRQ\n");
+		TftpRemoteIP = sip;
+		TftpRemotePort = src;
+		TftpOurPort = 1024 + (get_timer(0) % 3072);
+		new_transfer();
+		TftpSend(); /* Send ACK(0) */
+		break;
+#endif
+
+	case TFTP_OACK:
+		debug("Got OACK: %s %s\n",
+			pkt,
+			pkt + strlen((char *)pkt) + 1);
+		TftpState = STATE_OACK;
+		TftpRemotePort = src;
+		/*
+		 * Check for 'blksize' option.
+		 * Careful: "i" is signed, "len" is unsigned, thus
+		 * something like "len-8" may give a *huge* number
+		 */
+		for (i = 0; i+8 < len; i++) {
+			if (strcmp((char *)pkt+i, "blksize") == 0) {
+				TftpBlkSize = (unsigned short)
+					simple_strtoul((char *)pkt+i+8, NULL,
+						       10);
+				debug("Blocksize ack: %s, %d\n",
+					(char *)pkt+i+8, TftpBlkSize);
+			}
+#ifdef CONFIG_TFTP_TSIZE
+			if (strcmp((char *)pkt+i, "tsize") == 0) {
+				TftpTsize = simple_strtoul((char *)pkt+i+6,
+							   NULL, 10);
+				debug("size = %s, %d\n",
+					 (char *)pkt+i+6, TftpTsize);
+			}
+#endif
+		}
+#ifdef CONFIG_MCAST_TFTP
+		parse_multicast_oack((char *)pkt, len-1);
+		if ((Multicast) && (!MasterClient))
+			TftpState = STATE_DATA;	/* passive.. */
+		else
+#endif
+#ifdef CONFIG_CMD_TFTPPUT
+		if (TftpWriting) {
+			/* Get ready to send the first block */
+			TftpState = STATE_DATA;
+			TftpBlock++;
+		}
+#endif
+		TftpSend(); /* Send ACK or first data block */
+		break;
+	case TFTP_DATA:
+		if (len < 2)
+			return;
+		len -= 2;
+		TftpBlock = ntohs(*(ushort *)pkt);
+
+		update_block_number();
+
+		if (TftpState == STATE_SEND_RRQ)
+			debug("Server did not acknowledge timeout option!\n");
+
+		if (TftpState == STATE_SEND_RRQ || TftpState == STATE_OACK ||
+		    TftpState == STATE_RECV_WRQ) {
+			/* first block received */
+			TftpState = STATE_DATA;
+			TftpRemotePort = src;
+			new_transfer();
+
+#ifdef CONFIG_MCAST_TFTP
+			if (Multicast) { /* start!=1 common if mcast */
+				TftpLastBlock = TftpBlock - 1;
+			} else
+#endif
+			if (TftpBlock != 1) {	/* Assertion */
+				printf("\nTFTP error: "
+				       "First block is not block 1 (%ld)\n"
+				       "Starting again\n\n",
+					TftpBlock);
+				NetStartAgain();
+				break;
+			}
+		}
+
+		if (TftpBlock == TftpLastBlock) {
+			/*
+			 *	Same block again; ignore it.
+			 */
+			break;
+		}
+
+		TftpLastBlock = TftpBlock;
+		TftpTimeoutCountMax = TIMEOUT_COUNT;
+		NetSetTimeout(TftpTimeoutMSecs, TftpTimeout);
+
+		store_block(TftpBlock - 1, pkt + 2, len);
+
+		/*
+		 *	Acknowledge the block just received, which will prompt
+		 *	the remote for the next one.
+		 */
+#ifdef CONFIG_MCAST_TFTP
+		/* if I am the MasterClient, actively calculate what my next
+		 * needed block is; else I'm passive; not ACKING
+		 */
+		if (Multicast) {
+			if (len < TftpBlkSize)  {
+				TftpEndingBlock = TftpBlock;
+			} else if (MasterClient) {
+				TftpBlock = PrevBitmapHole =
+					ext2_find_next_zero_bit(
+						Bitmap,
+						(Mapsize*8),
+						PrevBitmapHole);
+				if (TftpBlock > ((Mapsize*8) - 1)) {
+					printf("tftpfile too big\n");
+					/* try to double it and retry */
+					Mapsize <<= 1;
+					mcast_cleanup();
+					NetStartAgain();
+					return;
+				}
+				TftpLastBlock = TftpBlock;
+			}
+		}
+#endif
+		TftpSend();
+
+#ifdef CONFIG_MCAST_TFTP
+		if (Multicast) {
+			if (MasterClient && (TftpBlock >= TftpEndingBlock)) {
+				puts("\nMulticast tftp done\n");
+				mcast_cleanup();
+				net_set_state(NETLOOP_SUCCESS);
+			}
+		} else
+#endif
+		if (len < TftpBlkSize)
+			tftp_complete();
+		break;
+
+	case TFTP_ERROR:
+		printf("\nTFTP error: '%s' (%d)\n",
+		       pkt + 2, ntohs(*(ushort *)pkt));
+
+		switch (ntohs(*(ushort *)pkt)) {
+		case TFTP_ERR_FILE_NOT_FOUND:
+		case TFTP_ERR_ACCESS_DENIED:
+			puts("Not retrying...\n");
+			eth_halt();
+			net_set_state(NETLOOP_FAIL);
+			break;
+		case TFTP_ERR_UNDEFINED:
+		case TFTP_ERR_DISK_FULL:
+		case TFTP_ERR_UNEXPECTED_OPCODE:
+		case TFTP_ERR_UNKNOWN_TRANSFER_ID:
+		case TFTP_ERR_FILE_ALREADY_EXISTS:
+		default:
+			puts("Starting again\n\n");
+#ifdef CONFIG_MCAST_TFTP
+			mcast_cleanup();
+#endif
+			NetStartAgain();
+			break;
+		}
+		break;
+	}
+}
+
+
+static int TftpTimeout(void)
+{
+	if (++TftpTimeoutCount > TftpTimeoutCountMax) {
+		++ tftp_server_cnt ;
+		restart("Retry count exceeded");
+	} else {
+		puts("T ");
+		NetSetTimeout(time_over, TftpTimeout);
+		if (TftpState != STATE_RECV_WRQ)
+		{	
+			TftpSend();
+		}
+	}
+	return 0;
+}
+
+
+int TftpStart(enum proto_t protocol)
+{
+	char *ep;             /* Environment pointer */
+
+	/*
+	 * Allow the user to choose TFTP blocksize and timeout.
+	 * TFTP protocol has a minimal timeout of 1 second.
+	 */
+	ep = getenv("tftpblocksize");
+	if (ep != NULL)
+		TftpBlkSizeOption = simple_strtol(ep, NULL, 10);
+
+	ep = getenv("tftptimeout");
+	if (ep != NULL)
+		TftpTimeoutMSecs = simple_strtol(ep, NULL, 10);
+
+	if (TftpTimeoutMSecs < 1000) {
+		printf("TFTP timeout (%ld ms) too low, "
+			"set minimum = 1000 ms\n",
+			TftpTimeoutMSecs);
+		TftpTimeoutMSecs = 1000;
+	}
+
+	debug("TFTP blocksize = %i, timeout = %ld ms\n",
+		TftpBlkSizeOption, TftpTimeoutMSecs);
+
+	TftpRemoteIP = NetServerIP;
+	if (BootFile[0] == '\0') {
+		sprintf(default_filename, "%02X%02X%02X%02X.img",
+			NetOurIP & 0xFF,
+			(NetOurIP >>  8) & 0xFF,
+			(NetOurIP >> 16) & 0xFF,
+			(NetOurIP >> 24) & 0xFF);
+
+		strncpy(tftp_filename, default_filename, MAX_LEN);
+		tftp_filename[MAX_LEN-1] = 0;
+
+		printf("*** Warning: no boot file name; using '%s'\n",
+			tftp_filename);
+	} else {
+		char *p = strchr(BootFile, ':');
+
+		if (p == NULL) {
+			strncpy(tftp_filename, BootFile, MAX_LEN - 1);
+			tftp_filename[MAX_LEN-1] = 0;
+		} else {
+			TftpRemoteIP = string_to_ip(BootFile);
+			strncpy(tftp_filename, p + 1, MAX_LEN - 1);
+			tftp_filename[MAX_LEN-1] = 0;
+		}
+	}
+
+	printf("Using %s device\n", eth_get_name());
+	printf("TFTP %s server %pI4; our IP address is %pI4",
+#ifdef CONFIG_CMD_TFTPPUT
+	       protocol == TFTPPUT ? "to" : "from",
+#else
+		"from",
+#endif
+		&TftpRemoteIP, &NetOurIP);
+
+	/* Check if we need to send across this subnet */
+	if (NetOurGatewayIP && NetOurSubnetMask) {
+		IPaddr_t OurNet	= NetOurIP    & NetOurSubnetMask;
+		IPaddr_t RemoteNet	= TftpRemoteIP & NetOurSubnetMask;
+
+		if (OurNet != RemoteNet)
+			printf("; sending through gateway %pI4",
+			       &NetOurGatewayIP);
+	}
+	putc('\n');
+
+	printf("Filename '%s'.", tftp_filename);
+
+	if (NetBootFileSize) {
+		printf(" Size is 0x%x Bytes = ", NetBootFileSize<<9);
+		print_size(NetBootFileSize<<9, "");
+	}
+
+	putc('\n');
+#ifdef CONFIG_CMD_TFTPPUT
+	TftpWriting = (protocol == TFTPPUT);
+	if (TftpWriting) {
+		printf("Save address: 0x%lx\n", save_addr);
+		printf("Save size:    0x%lx\n", save_size);
+		NetBootFileXferSize = save_size;
+		puts("Saving: *\b");
+		TftpState = STATE_SEND_WRQ;
+		new_transfer();
+	} else
+#endif
+	{
+		printf("Load address: 0x%lx\n", load_addr);
+		puts("Loading: *\b");
+		TftpState = STATE_SEND_RRQ;
+	}
+
+	time_start = get_timer(0);
+	TftpTimeoutCountMax = TftpRRQTimeoutCountMax;
+
+	NetSetTimeout(TftpTimeoutMSecs, TftpTimeout);
+	net_set_udp_handler(TftpHandler);
+#ifdef CONFIG_CMD_TFTPPUT
+	net_set_icmp_handler(icmp_handler);
+#endif
+	TftpRemotePort = WELL_KNOWN_PORT;
+	TftpTimeoutCount = 0;
+	/* Use a pseudo-random port unless a specific port is set */
+	TftpOurPort = 1024 + (get_timer(0) % 3072);
+
+#ifdef CONFIG_TFTP_PORT
+	ep = getenv("tftpdstp");
+	if (ep != NULL)
+		TftpRemotePort = simple_strtol(ep, NULL, 10);
+	ep = getenv("tftpsrcp");
+	if (ep != NULL)
+		TftpOurPort = simple_strtol(ep, NULL, 10);
+#endif
+	TftpBlock = 0;
+
+	/* zero out server ether in case the server ip has changed */
+	memset(NetServerEther, 0, 6);
+	/* Revert TftpBlkSize to dflt */
+	TftpBlkSize = TFTP_BLOCK_SIZE;
+#ifdef CONFIG_MCAST_TFTP
+	mcast_cleanup();
+#endif
+#ifdef CONFIG_TFTP_TSIZE
+	TftpTsize = 0;
+	TftpNumchars = 0;
+#endif
+
+	TftpSend();
+		
+	return 0;
+}
+
+#ifdef CONFIG_CMD_TFTPSRV
+void
+TftpStartServer(void)
+{
+	tftp_filename[0] = 0;
+
+	printf("Using %s device\n", eth_get_name());
+	printf("Listening for TFTP transfer on %pI4\n", &NetOurIP);
+	printf("Load address: 0x%lx\n", load_addr);
+
+	puts("Loading: *\b");
+
+	TftpTimeoutCountMax = TIMEOUT_COUNT;
+	TftpTimeoutCount = 0;
+	TftpTimeoutMSecs = TIMEOUT;
+	NetSetTimeout(TftpTimeoutMSecs, TftpTimeout);
+
+	/* Revert TftpBlkSize to dflt */
+	TftpBlkSize = TFTP_BLOCK_SIZE;
+	TftpBlock = 0;
+	TftpOurPort = WELL_KNOWN_PORT;
+
+#ifdef CONFIG_TFTP_TSIZE
+	TftpTsize = 0;
+	TftpNumchars = 0;
+#endif
+
+	TftpState = STATE_RECV_WRQ;
+	net_set_udp_handler(TftpHandler);
+}
+#endif /* CONFIG_CMD_TFTPSRV */
+
+#ifdef CONFIG_MCAST_TFTP
+/* Credits: atftp project.
+ */
+
+/* pick up BcastAddr, Port, and whether I am [now] the master-client. *
+ * Frame:
+ *    +-------+-----------+---+-------~~-------+---+
+ *    |  opc  | multicast | 0 | addr, port, mc | 0 |
+ *    +-------+-----------+---+-------~~-------+---+
+ * The multicast addr/port becomes what I listen to, and if 'mc' is '1' then
+ * I am the new master-client so must send ACKs to DataBlocks.  If I am not
+ * master-client, I'm a passive client, gathering what DataBlocks I may and
+ * making note of which ones I got in my bitmask.
+ * In theory, I never go from master->passive..
+ * .. this comes in with pkt already pointing just past opc
+ */
+static void parse_multicast_oack(char *pkt, int len)
+{
+	int i;
+	IPaddr_t addr;
+	char *mc_adr, *port,  *mc;
+
+	mc_adr = port = mc = NULL;
+	/* march along looking for 'multicast\0', which has to start at least
+	 * 14 bytes back from the end.
+	 */
+	for (i = 0; i < len-14; i++)
+		if (strcmp(pkt+i, "multicast") == 0)
+			break;
+	if (i >= (len-14)) /* non-Multicast OACK, ign. */
+		return;
+
+	i += 10; /* strlen multicast */
+	mc_adr = pkt+i;
+	for (; i < len; i++) {
+		if (*(pkt+i) == ',') {
+			*(pkt+i) = '\0';
+			if (port) {
+				mc = pkt+i+1;
+				break;
+			} else {
+				port = pkt+i+1;
+			}
+		}
+	}
+	if (!port || !mc_adr || !mc)
+		return;
+	if (Multicast && MasterClient) {
+		printf("I got a OACK as master Client, WRONG!\n");
+		return;
+	}
+	/* ..I now accept packets destined for this MCAST addr, port */
+	if (!Multicast) {
+		if (Bitmap) {
+			printf("Internal failure! no mcast.\n");
+			free(Bitmap);
+			Bitmap = NULL;
+			ProhibitMcast = 1;
+			return ;
+		}
+		/* I malloc instead of pre-declare; so that if the file ends
+		 * up being too big for this bitmap I can retry
+		 */
+		Bitmap = malloc(Mapsize);
+		if (!Bitmap) {
+			printf("No Bitmap, no multicast. Sorry.\n");
+			ProhibitMcast = 1;
+			return;
+		}
+		memset(Bitmap, 0, Mapsize);
+		PrevBitmapHole = 0;
+		Multicast = 1;
+	}
+	addr = string_to_ip(mc_adr);
+	if (Mcast_addr != addr) {
+		if (Mcast_addr)
+			eth_mcast_join(Mcast_addr, 0);
+		Mcast_addr = addr;
+		if (eth_mcast_join(Mcast_addr, 1)) {
+			printf("Fail to set mcast, revert to TFTP\n");
+			ProhibitMcast = 1;
+			mcast_cleanup();
+			NetStartAgain();
+		}
+	}
+	MasterClient = (unsigned char)simple_strtoul((char *)mc, NULL, 10);
+	Mcast_port = (unsigned short)simple_strtoul(port, NULL, 10);
+	printf("Multicast: %s:%d [%d]\n", mc_adr, Mcast_port, MasterClient);
+	return;
+}
+
+#endif /* Multicast TFTP */
diff --git a/boot/common/src/uboot/net/tftp.h b/boot/common/src/uboot/net/tftp.h
new file mode 100644
index 0000000..d0ffb1f
--- /dev/null
+++ b/boot/common/src/uboot/net/tftp.h
@@ -0,0 +1,30 @@
+/*
+ *	LiMon - BOOTP/TFTP.
+ *
+ *	Copyright 1994, 1995, 2000 Neil Russell.
+ *	Copyright 2011 Comelit Group SpA
+ *	               Luca Ceresoli <luca.ceresoli@comelit.it>
+ *	(See License)
+ */
+
+#ifndef __TFTP_H__
+#define __TFTP_H__
+
+/**********************************************************************/
+/*
+ *	Global functions and variables.
+ */
+
+/* tftp.c */
+int TftpStart(enum proto_t protocol);	/* Begin TFTP get/put */
+
+#ifdef CONFIG_CMD_TFTPSRV
+extern void TftpStartServer(void);	/* Wait for incoming TFTP put */
+#endif
+
+extern ulong TftpRRQTimeoutMSecs;
+extern int TftpRRQTimeoutCountMax;
+
+/**********************************************************************/
+
+#endif /* __TFTP_H__ */