summaryrefslogtreecommitdiffstats
path: root/u-boot/net
diff options
context:
space:
mode:
authorH. Nikolaus Schaller <hns@goldelico.com>2012-03-26 20:55:28 +0200
committerH. Nikolaus Schaller <hns@goldelico.com>2012-03-26 20:55:28 +0200
commit92988a21ad4c4c9504295ccb580c9f806134471b (patch)
tree5effc9f14170112450de05c67dafbe8d5034d595 /u-boot/net
parentca2b506783b676c95762c54ea24dcfdaae1947c9 (diff)
downloadbootable_bootloader_goldelico_gta04-92988a21ad4c4c9504295ccb580c9f806134471b.zip
bootable_bootloader_goldelico_gta04-92988a21ad4c4c9504295ccb580c9f806134471b.tar.gz
bootable_bootloader_goldelico_gta04-92988a21ad4c4c9504295ccb580c9f806134471b.tar.bz2
added boot script files to repository
Diffstat (limited to 'u-boot/net')
-rw-r--r--u-boot/net/Makefile55
-rw-r--r--u-boot/net/bootp.c952
-rw-r--r--u-boot/net/bootp.h95
-rw-r--r--u-boot/net/dns.c210
-rw-r--r--u-boot/net/dns.h39
-rw-r--r--u-boot/net/eth.c540
-rw-r--r--u-boot/net/net.c1934
-rw-r--r--u-boot/net/nfs.c755
-rw-r--r--u-boot/net/nfs.h80
-rw-r--r--u-boot/net/rarp.c116
-rw-r--r--u-boot/net/rarp.h44
-rw-r--r--u-boot/net/sntp.c88
-rw-r--r--u-boot/net/sntp.h61
-rw-r--r--u-boot/net/tftp.c729
-rw-r--r--u-boot/net/tftp.h21
15 files changed, 5719 insertions, 0 deletions
diff --git a/u-boot/net/Makefile b/u-boot/net/Makefile
new file mode 100644
index 0000000..0544f6b
--- /dev/null
+++ b/u-boot/net/Makefile
@@ -0,0 +1,55 @@
+#
+# (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) += bootp.o
+COBJS-$(CONFIG_CMD_DNS) += dns.o
+COBJS-$(CONFIG_CMD_NET) += eth.o
+COBJS-$(CONFIG_CMD_NET) += net.o
+COBJS-$(CONFIG_CMD_NFS) += nfs.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/u-boot/net/bootp.c b/u-boot/net/bootp.c
new file mode 100644
index 0000000..1a71786
--- /dev/null
+++ b/u-boot/net/bootp.c
@@ -0,0 +1,952 @@
+/*
+ * 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
+
+#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;
+#ifdef CONFIG_BOOTP_RANDOM_DELAY
+ulong seed1, seed2;
+#endif
+
+#if defined(CONFIG_CMD_DHCP)
+dhcp_state_t dhcp_state = INIT;
+unsigned long dhcp_leasetime = 0;
+IPaddr_t NetDHCPServerIP = 0;
+static void DhcpHandler(uchar * pkt, unsigned dest, 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
+
+#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
+
+#endif
+
+static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len)
+{
+ Bootp_t *bp = (Bootp_t *) pkt;
+ int retval = 0;
+
+ if (dest != PORT_BOOTPC || src != PORT_BOOTPS)
+ retval = -1;
+ else if (len < sizeof (Bootp_t) - OPT_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(Bootp_t *bp)
+{
+ IPaddr_t tmp_ip;
+
+ NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
+#if !defined(CONFIG_BOOTP_SERVERIP)
+ NetCopyIP(&tmp_ip, &bp->bp_siaddr);
+ if (tmp_ip != 0)
+ NetCopyIP(&NetServerIP, &bp->bp_siaddr);
+ memcpy (NetServerEther, ((Ethernet_t *)NetRxPacket)->et_src, 6);
+#endif
+ 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;
+ /* 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);
+}
+/*
+ * Handle a BOOTP received packet.
+ */
+static void
+BootpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
+{
+ Bootp_t *bp;
+ char *s;
+
+ debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n",
+ src, dest, len, sizeof (Bootp_t));
+
+ bp = (Bootp_t *)pkt;
+
+ if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
+ 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);
+
+ debug("Got good BOOTP\n");
+
+ if ((s = getenv("autoload")) != NULL) {
+ if (*s == 'n') {
+ /*
+ * Just use BOOTP to configure system;
+ * Do not use TFTP to load the bootfile.
+ */
+ NetState = NETLOOP_SUCCESS;
+ return;
+#if defined(CONFIG_CMD_NFS)
+ } else if (strcmp(s, "NFS") == 0) {
+ /*
+ * Use NFS to load the bootfile.
+ */
+ NfsStart();
+ return;
+#endif
+ }
+ }
+
+ TftpStart();
+}
+#endif
+
+/*
+ * Timeout on BOOTP/DHCP request.
+ */
+static void
+BootpTimeout(void)
+{
+ if (BootpTry >= TIMEOUT_COUNT) {
+ puts ("\nRetry count exceeded; starting again\n");
+ NetStartAgain ();
+ } else {
+ NetSetTimeout (TIMEOUT, BootpTimeout);
+ BootpRequest ();
+ }
+}
+
+/*
+ * 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_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_SIZE) >> 8;
+ *e++ = (576 - 312 + OPT_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)
+ if ((hostname = getenv ("hostname"))) {
+ int hostnamelen = strlen (hostname);
+
+ *e++ = 12; /* Hostname */
+ *e++ = hostnamelen;
+ memcpy (e, hostname, hostnamelen);
+ e += hostnamelen;
+ }
+#endif
+
+#if defined(CONFIG_BOOTP_VENDOREX)
+ if ((x = dhcp_vendorex_prep (e)))
+ 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_SIZE) >> 16;
+ *e++ = (576 - 312 + OPT_SIZE) & 0xff;
+#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
+
+ *e++ = 255; /* End of the list */
+
+ return e - start;
+}
+#endif
+
+void
+BootpRequest (void)
+{
+ volatile uchar *pkt, *iphdr;
+ Bootp_t *bp;
+ int ext_len, pktlen, iplen;
+
+#if defined(CONFIG_CMD_DHCP)
+ dhcp_state = INIT;
+#endif
+
+#ifdef CONFIG_BOOTP_RANDOM_DELAY /* Random BOOTP delay */
+ unsigned char bi_enetaddr[6];
+ int reg;
+ ulong tst1, tst2, sum, m_mask, m_value = 0;
+
+ if (BootpTry ==0) {
+ /* get our mac */
+ eth_getenv_enetaddr("ethaddr", bi_enetaddr);
+
+ debug("BootpRequest => Our Mac: ");
+ for (reg=0; reg<6; reg++)
+ debug("%x%c", bi_enetaddr[reg], reg==5 ? '\n' : ':');
+
+ /* Mac-Manipulation 2 get seed1 */
+ tst1=0;
+ tst2=0;
+ for (reg=2; reg<6; reg++) {
+ tst1 = tst1 << 8;
+ tst1 = tst1 | bi_enetaddr[reg];
+ }
+ for (reg=0; reg<2; reg++) {
+ tst2 = tst2 | bi_enetaddr[reg];
+ tst2 = tst2 << 8;
+ }
+
+ seed1 = tst1^tst2;
+
+ /* Mirror seed1*/
+ m_mask=0x1;
+ for (reg=1;reg<=32;reg++) {
+ m_value |= (m_mask & seed1);
+ seed1 = seed1 >> 1;
+ m_value = m_value << 1;
+ }
+ seed1 = m_value;
+ seed2 = 0xB78D0945;
+ }
+
+ /* Random Number Generator */
+
+ for (reg=0;reg<=0;reg++) {
+ sum = seed1 + seed2;
+ if (sum < seed1 || sum < seed2)
+ sum++;
+ seed2 = seed1;
+ seed1 = sum;
+
+ if (BootpTry<=2) { /* Start with max 1024 * 1ms */
+ sum = sum >> (22-BootpTry);
+ } else { /*After 3rd BOOTP request max 8192 * 1ms */
+ sum = sum >> 19;
+ }
+ }
+
+ printf ("Random delay: %ld ms...\n", sum);
+ for (reg=0; reg <sum; reg++) {
+ udelay(1000); /*Wait 1ms*/
+ }
+#endif /* CONFIG_BOOTP_RANDOM_DELAY */
+
+ printf("BOOTP broadcast %d\n", ++BootpTry);
+ pkt = NetTxPacket;
+ memset ((void*)pkt, 0, PKTSIZE);
+
+ pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
+
+ /*
+ * 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.
+ */
+ /* NetSetIP(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, sizeof (Bootp_t)); */
+ iphdr = pkt; /* We need this later for NetSetIP() */
+ pkt += IP_HDR_SIZE;
+
+ bp = (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)
+ ext_len = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0);
+#else
+ ext_len = 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
+ */
+ pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
+ iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + ext_len;
+ NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
+ NetSetTimeout(SELECT_TIMEOUT, BootpTimeout);
+
+#if defined(CONFIG_CMD_DHCP)
+ dhcp_state = SELECTING;
+ NetSetHandler(DhcpHandler);
+#else
+ NetSetHandler(BootpHandler);
+#endif
+ NetSendPacket(NetTxPacket, pktlen);
+}
+
+#if defined(CONFIG_CMD_DHCP)
+static void DhcpOptionsProcess (uchar * popt, 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;
+#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(Bootp_t *bp_offer)
+{
+ volatile uchar *pkt, *iphdr;
+ Bootp_t *bp;
+ int pktlen, iplen, extlen;
+ IPaddr_t OfferedIP;
+
+ debug("DhcpSendRequestPkt: Sending DHCPREQUEST\n");
+ pkt = NetTxPacket;
+ memset ((void*)pkt, 0, PKTSIZE);
+
+ pkt += NetSetEther(pkt, NetBcastAddr, PROT_IP);
+
+ iphdr = pkt; /* We'll need this later to set proper pkt size */
+ pkt += IP_HDR_SIZE;
+
+ bp = (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);
+
+ pktlen = ((int)(pkt-NetTxPacket)) + BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
+ iplen = BOOTP_HDR_SIZE - sizeof(bp->bp_vend) + extlen;
+ NetSetIP(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen);
+
+ debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen);
+#ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY
+ udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY);
+#endif /* CONFIG_BOOTP_DHCP_REQUEST_DELAY */
+ NetSendPacket(NetTxPacket, pktlen);
+}
+
+/*
+ * Handle DHCP received packets.
+ */
+static void
+DhcpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
+{
+ Bootp_t *bp = (Bootp_t *)pkt;
+
+ debug("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n",
+ src, dest, len, dhcp_state);
+
+ if (BootpCheckPkt(pkt, dest, src, len)) /* Filter out pkts we don't want */
+ 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 ) {
+ char *s;
+
+ if (NetReadLong((ulong*)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC))
+ DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp);
+ BootpCopyNetParams(bp); /* Store net params from reply */
+ dhcp_state = BOUND;
+ printf ("DHCP client bound to address %pI4\n", &NetOurIP);
+
+ /* Obey the 'autoload' setting */
+ if ((s = getenv("autoload")) != NULL) {
+ if (*s == 'n') {
+ /*
+ * Just use BOOTP to configure system;
+ * Do not use TFTP to load the bootfile.
+ */
+ NetState = NETLOOP_SUCCESS;
+ return;
+#if defined(CONFIG_CMD_NFS)
+ } else if (strcmp(s, "NFS") == 0) {
+ /*
+ * Use NFS to load the bootfile.
+ */
+ NfsStart();
+ return;
+#endif
+ }
+ }
+ TftpStart();
+ 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/u-boot/net/bootp.h b/u-boot/net/bootp.h
new file mode 100644
index 0000000..50625ab
--- /dev/null
+++ b/u-boot/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)
+#define OPT_SIZE 312 /* Minimum DHCP Options size per RFC2131 - results in 576 byte pkt */
+#else
+#define OPT_SIZE 64
+#endif
+
+typedef struct
+{
+ 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_SIZE]; /* Vendor information */
+} Bootp_t;
+
+#define BOOTP_HDR_SIZE sizeof (Bootp_t)
+#define BOOTP_SIZE (ETHER_HDR_SIZE + IP_HDR_SIZE + BOOTP_HDR_SIZE)
+
+/**********************************************************************/
+/*
+ * Global functions and variables.
+ */
+
+/* bootp.c */
+extern ulong BootpID; /* ID of cur BOOTP request */
+extern char BootFile[128]; /* Boot file name */
+extern int BootpTry;
+#ifdef CONFIG_BOOTP_RANDOM_DELAY
+extern ulong seed1, seed2; /* seed for random BOOTP delay */
+#endif
+
+
+/* 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/u-boot/net/dns.c b/u-boot/net/dns.c
new file mode 100644
index 0000000..bb3e3f5
--- /dev/null
+++ b/u-boot/net/dns.c
@@ -0,0 +1,210 @@
+/*
+ * 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 "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_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");
+ NetState = NETLOOP_FAIL;
+}
+
+static void
+DnsHandler(uchar *pkt, unsigned dest, 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;
+ short tmp;
+
+
+ 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 1 query. We want to see more that 1 answer. */
+ header = (struct header *) pkt;
+ if (ntohs(header->nqueries) != 1)
+ return;
+
+ /* Received 0 answers */
+ if (header->nanswers == 0) {
+ puts("DNS server returned no answers\n");
+ NetState = 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 */
+ tmp = p[1] | (p[2] << 8);
+ if (&p[5] > e || ntohs(tmp) != DNS_A_RECORD) {
+ puts("DNS response was not A record\n");
+ NetState = 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]);
+
+ tmp = p[2] | (p[3] << 8);
+ type = ntohs(tmp);
+ debug("type = %d\n", type);
+ if (type == DNS_CNAME_RECORD) {
+ /* CNAME answer. shift to the next section */
+ debug("Found canonical name\n");
+ tmp = p[10] | (p[11] << 8);
+ dlen = ntohs(tmp);
+ 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) {
+
+ tmp = p[10] | (p[11] << 8);
+ dlen = ntohs(tmp);
+ 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");
+ }
+
+ NetState = NETLOOP_SUCCESS;
+}
+
+void
+DnsStart(void)
+{
+ debug("%s\n", __func__);
+
+ NetSetTimeout(DNS_TIMEOUT, DnsTimeout);
+ NetSetHandler(DnsHandler);
+
+ DnsSend();
+}
diff --git a/u-boot/net/dns.h b/u-boot/net/dns.h
new file mode 100644
index 0000000..277c093
--- /dev/null
+++ b/u-boot/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/u-boot/net/eth.c b/u-boot/net/eth.c
new file mode 100644
index 0000000..3a7ff50
--- /dev/null
+++ b/u-boot/net/eth.c
@@ -0,0 +1,540 @@
+/*
+ * (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>
+
+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(int index, uchar *enetaddr)
+{
+ char enetvar[32];
+ sprintf(enetvar, index ? "eth%daddr" : "ethaddr", index);
+ return eth_getenv_enetaddr(enetvar, enetaddr);
+}
+
+#ifdef CONFIG_NET_MULTI
+
+static int eth_mac_skip(int index)
+{
+ char enetvar[15];
+ char *skip_state;
+ sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
+ return ((skip_state = getenv(enetvar)) != NULL);
+}
+
+/*
+ * 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")));
+
+extern int mv6436x_eth_initialize(bd_t *);
+extern int mv6446x_eth_initialize(bd_t *);
+
+#ifdef CONFIG_API
+extern void (*push_packet)(volatile void *, int);
+
+static struct {
+ uchar data[PKTSIZE];
+ int length;
+} eth_rcv_bufs[PKTBUFSRX];
+
+static unsigned int eth_rcv_current = 0, eth_rcv_last = 0;
+#endif
+
+static struct eth_device *eth_devices, *eth_current;
+
+struct eth_device *eth_get_dev(void)
+{
+ return eth_current;
+}
+
+struct eth_device *eth_get_dev_by_name(const char *devname)
+{
+ struct eth_device *dev, *target_dev;
+
+ 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;
+ int idx = 0;
+
+ if (!eth_devices)
+ return NULL;
+
+ dev = eth_devices;
+ target_dev = NULL;
+ do {
+ if (idx == index) {
+ target_dev = dev;
+ break;
+ }
+ dev = dev->next;
+ idx++;
+ } while (dev != eth_devices);
+
+ return target_dev;
+}
+
+int eth_get_dev_index (void)
+{
+ struct eth_device *dev;
+ int num = 0;
+
+ if (!eth_devices) {
+ return (-1);
+ }
+
+ for (dev = eth_devices; dev; dev = dev->next) {
+ if (dev == eth_current)
+ break;
+ ++num;
+ }
+
+ if (dev) {
+ return (num);
+ }
+
+ return (0);
+}
+
+static void eth_current_changed(void)
+{
+#ifdef CONFIG_NET_MULTI
+ {
+ 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);
+ }
+#endif
+}
+
+int eth_register(struct eth_device *dev)
+{
+ struct eth_device *d;
+ 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;
+
+ return 0;
+}
+
+int eth_initialize(bd_t *bis)
+{
+ unsigned char env_enetaddr[6];
+ int eth_number = 0;
+
+ eth_devices = NULL;
+ eth_current = NULL;
+
+ show_boot_progress (64);
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_init();
+#endif
+ /*
+ * 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 defined(CONFIG_DB64360) || defined(CONFIG_CPCI750)
+ mv6436x_eth_initialize(bis);
+#endif
+#if defined(CONFIG_DB64460) || defined(CONFIG_P3Mx)
+ mv6446x_eth_initialize(bis);
+#endif
+ if (!eth_devices) {
+ puts ("No ethernet found.\n");
+ show_boot_progress (-64);
+ } else {
+ struct eth_device *dev = eth_devices;
+ char *ethprime = getenv ("ethprime");
+
+ show_boot_progress (65);
+ do {
+ if (eth_number)
+ 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");
+
+ eth_getenv_enetaddr_by_index(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);
+ }
+ if (dev->write_hwaddr &&
+ !eth_mac_skip(eth_number) &&
+ is_valid_ether_addr(dev->enetaddr)) {
+ dev->write_hwaddr(dev);
+ }
+
+ eth_number++;
+ dev = dev->next;
+ } while(dev != eth_devices);
+
+ eth_current_changed();
+ putc ('\n');
+ }
+
+ return eth_number;
+}
+
+#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)
+{
+ int eth_number;
+ struct eth_device *old_current, *dev;
+
+ if (!eth_current) {
+ puts ("No ethernet found.\n");
+ return -1;
+ }
+
+ /* Sync environment with network devices */
+ eth_number = 0;
+ dev = eth_devices;
+ do {
+ uchar env_enetaddr[6];
+
+ if (eth_getenv_enetaddr_by_index(eth_number, env_enetaddr))
+ memcpy(dev->enetaddr, env_enetaddr, 6);
+
+ ++eth_number;
+ 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(volatile 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(volatile void *packet, int length)
+{
+ volatile 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(volatile void *packet, int length)
+{
+ volatile 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;
+ }
+
+ if (length < eth_rcv_bufs[eth_rcv_current].length)
+ return -1;
+
+ length = eth_rcv_bufs[eth_rcv_current].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 = NULL;
+ char *ethrotate;
+
+ /*
+ * Do not rotate between network interfaces when
+ * 'ethrotate' variable is set to 'no'.
+ */
+ if (((ethrotate = getenv ("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 = NULL;
+ static int env_changed_id = 0;
+ 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");
+}
+
+#else /* !CONFIG_NET_MULTI */
+
+#warning Ethernet driver is deprecated. Please update to use CONFIG_NET_MULTI
+
+extern int at91rm9200_miiphy_initialize(bd_t *bis);
+extern int mcf52x2_miiphy_initialize(bd_t *bis);
+extern int ns7520_miiphy_initialize(bd_t *bis);
+
+
+int eth_initialize(bd_t *bis)
+{
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+ miiphy_init();
+#endif
+
+#if defined(CONFIG_AT91RM9200)
+ at91rm9200_miiphy_initialize(bis);
+#endif
+#if defined(CONFIG_MCF52x2)
+ mcf52x2_miiphy_initialize(bis);
+#endif
+#if defined(CONFIG_DRIVER_NS7520_ETHERNET)
+ ns7520_miiphy_initialize(bis);
+#endif
+ return 0;
+}
+#endif
diff --git a/u-boot/net/net.c b/u-boot/net/net.c
new file mode 100644
index 0000000..a609632
--- /dev/null
+++ b/u-boot/net/net.c
@@ -0,0 +1,1934 @@
+/*
+ * 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
+ *
+ * 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 <watchdog.h>
+#include <command.h>
+#include <net.h>
+#include "bootp.h"
+#include "tftp.h"
+#ifdef CONFIG_CMD_RARP
+#include "rarp.h"
+#endif
+#include "nfs.h"
+#ifdef CONFIG_STATUS_LED
+#include <status_led.h>
+#include <miiphy.h>
+#endif
+#if defined(CONFIG_CMD_SNTP)
+#include "sntp.h"
+#endif
+#if defined(CONFIG_CDP_VERSION)
+#include <timestamp.h>
+#endif
+#if defined(CONFIG_CMD_DNS)
+#include "dns.h"
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_ARP_TIMEOUT
+# define ARP_TIMEOUT 5000UL /* Milliseconds before trying ARP again */
+#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
+
+/** BOOTP EXTENTIONS **/
+
+IPaddr_t NetOurSubnetMask=0; /* Our subnet mask (0=unknown) */
+IPaddr_t NetOurGatewayIP=0; /* Our gateways IP address */
+IPaddr_t NetOurDNSIP=0; /* Our DNS IP address */
+#if defined(CONFIG_BOOTP_DNS2)
+IPaddr_t NetOurDNS2IP=0; /* Our 2nd DNS IP address */
+#endif
+char NetOurNISDomain[32]={0,}; /* Our NIS domain */
+char NetOurHostName[32]={0,}; /* Our hostname */
+char NetOurRootPath[64]={0,}; /* Our bootpath */
+ushort NetBootFileSize=0; /* Our bootfile size in blocks */
+
+#ifdef CONFIG_MCAST_TFTP /* Multicast TFTP */
+IPaddr_t Mcast_addr;
+#endif
+
+/** END OF BOOTP EXTENTIONS **/
+
+ulong NetBootFileXferSize; /* The actual transferred size of the bootfile (in bytes) */
+uchar NetOurEther[6]; /* Our ethernet address */
+uchar NetServerEther[6] = /* Boot server enet address */
+ { 0, 0, 0, 0, 0, 0 };
+IPaddr_t NetOurIP; /* Our IP addr (0 = unknown) */
+IPaddr_t NetServerIP; /* Server IP addr (0 = unknown) */
+volatile uchar *NetRxPacket; /* Current receive packet */
+int NetRxPacketLen; /* Current rx packet length */
+unsigned NetIPID; /* IP packet ID */
+uchar NetBcastAddr[6] = /* Ethernet bcast address */
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+uchar NetEtherNullAddr[6] =
+ { 0, 0, 0, 0, 0, 0 };
+#ifdef CONFIG_API
+void (*push_packet)(volatile void *, int len) = 0;
+#endif
+#if defined(CONFIG_CMD_CDP)
+uchar NetCDPAddr[6] = /* Ethernet bcast address */
+ { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
+#endif
+int NetState; /* Network loop state */
+#ifdef CONFIG_NET_MULTI
+int NetRestartWrap = 0; /* Tried all network devices */
+static int NetRestarted = 0; /* Network loop restarted */
+static int NetDevExists = 0; /* At least one device configured */
+#endif
+
+/* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
+ushort NetOurVLAN = 0xFFFF; /* default is without VLAN */
+ushort NetOurNativeVLAN = 0xFFFF; /* ditto */
+
+char BootFile[128]; /* Boot File name */
+
+#if defined(CONFIG_CMD_PING)
+IPaddr_t NetPingIP; /* the ip address to ping */
+
+static void PingStart(void);
+#endif
+
+#if defined(CONFIG_CMD_CDP)
+static void CDPStart(void);
+#endif
+
+#if defined(CONFIG_CMD_SNTP)
+IPaddr_t NetNtpServerIP; /* NTP server IP address */
+int NetTimeOffset=0; /* offset time from UTC */
+#endif
+
+#ifdef CONFIG_NETCONSOLE
+void NcStart(void);
+int nc_input_packet(uchar *pkt, unsigned dest, unsigned src, unsigned len);
+#endif
+
+volatile uchar PktBuf[(PKTBUFSRX+1) * PKTSIZE_ALIGN + PKTALIGN];
+
+volatile uchar *NetRxPackets[PKTBUFSRX]; /* Receive packets */
+
+static rxhand_f *packetHandler; /* Current RX packet handler */
+static thand_f *timeHandler; /* Current timeout handler */
+static ulong timeStart; /* Time base value */
+static ulong timeDelta; /* Current timeout value */
+volatile uchar *NetTxPacket = 0; /* THE transmit packet */
+
+static int net_check_prereq (proto_t protocol);
+
+static int NetTryCount;
+
+/**********************************************************************/
+
+IPaddr_t NetArpWaitPacketIP;
+IPaddr_t NetArpWaitReplyIP;
+uchar *NetArpWaitPacketMAC; /* MAC address of waiting packet's destination */
+uchar *NetArpWaitTxPacket; /* THE transmit packet */
+int NetArpWaitTxPacketSize;
+uchar NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
+ulong NetArpWaitTimerStart;
+int NetArpWaitTry;
+
+void ArpRequest (void)
+{
+ int i;
+ volatile uchar *pkt;
+ ARP_t *arp;
+
+ debug("ARP broadcast %d\n", NetArpWaitTry);
+
+ pkt = NetTxPacket;
+
+ pkt += NetSetEther (pkt, NetBcastAddr, PROT_ARP);
+
+ arp = (ARP_t *) pkt;
+
+ arp->ar_hrd = htons (ARP_ETHER);
+ arp->ar_pro = htons (PROT_IP);
+ arp->ar_hln = 6;
+ arp->ar_pln = 4;
+ arp->ar_op = htons (ARPOP_REQUEST);
+
+ memcpy (&arp->ar_data[0], NetOurEther, 6); /* source ET addr */
+ NetWriteIP ((uchar *) & arp->ar_data[6], NetOurIP); /* source IP addr */
+ for (i = 10; i < 16; ++i) {
+ arp->ar_data[i] = 0; /* dest ET addr = 0 */
+ }
+
+ if ((NetArpWaitPacketIP & NetOurSubnetMask) !=
+ (NetOurIP & NetOurSubnetMask)) {
+ if (NetOurGatewayIP == 0) {
+ puts ("## Warning: gatewayip needed but not set\n");
+ NetArpWaitReplyIP = NetArpWaitPacketIP;
+ } else {
+ NetArpWaitReplyIP = NetOurGatewayIP;
+ }
+ } else {
+ NetArpWaitReplyIP = NetArpWaitPacketIP;
+ }
+
+ NetWriteIP ((uchar *) & arp->ar_data[16], NetArpWaitReplyIP);
+ (void) eth_send (NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);
+}
+
+void ArpTimeoutCheck(void)
+{
+ ulong t;
+
+ if (!NetArpWaitPacketIP)
+ return;
+
+ t = get_timer(0);
+
+ /* check for arp timeout */
+ if ((t - NetArpWaitTimerStart) > ARP_TIMEOUT) {
+ NetArpWaitTry++;
+
+ if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
+ puts ("\nARP Retry count exceeded; starting again\n");
+ NetArpWaitTry = 0;
+ NetStartAgain();
+ } else {
+ NetArpWaitTimerStart = t;
+ ArpRequest();
+ }
+ }
+}
+
+static void
+NetInitLoop(proto_t protocol)
+{
+ static int env_changed_id = 0;
+ bd_t *bd = gd->bd;
+ int env_id = get_env_id ();
+
+ /* update only when the environment has changed */
+ if (env_changed_id != env_id) {
+ NetCopyIP(&NetOurIP, &bd->bi_ip_addr);
+ 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;
+ }
+
+ return;
+}
+
+/**********************************************************************/
+/*
+ * Main network processing loop.
+ */
+
+int
+NetLoop(proto_t protocol)
+{
+ bd_t *bd = gd->bd;
+
+#ifdef CONFIG_NET_MULTI
+ NetRestarted = 0;
+ NetDevExists = 0;
+#endif
+
+ /* XXX problem with bss workaround */
+ NetArpWaitPacketMAC = NULL;
+ NetArpWaitTxPacket = NULL;
+ NetArpWaitPacketIP = 0;
+ NetArpWaitReplyIP = 0;
+ NetArpWaitTxPacket = NULL;
+ NetTxPacket = NULL;
+ NetTryCount = 1;
+
+ if (!NetTxPacket) {
+ int i;
+ /*
+ * Setup packet buffers, aligned correctly.
+ */
+ NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
+ NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
+ for (i = 0; i < PKTBUFSRX; i++) {
+ NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
+ }
+ }
+
+ if (!NetArpWaitTxPacket) {
+ NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
+ NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
+ NetArpWaitTxPacketSize = 0;
+ }
+
+ eth_halt();
+#ifdef CONFIG_NET_MULTI
+ eth_set_current();
+#endif
+ if (eth_init(bd) < 0) {
+ eth_halt();
+ return(-1);
+ }
+
+restart:
+#ifdef CONFIG_NET_MULTI
+ memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
+#else
+ eth_getenv_enetaddr("ethaddr", NetOurEther);
+#endif
+
+ NetState = 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.
+ */
+ NetInitLoop(protocol);
+
+ switch (net_check_prereq (protocol)) {
+ case 1:
+ /* network not configured */
+ eth_halt();
+ return (-1);
+
+#ifdef CONFIG_NET_MULTI
+ case 2:
+ /* network device not configured */
+ break;
+#endif /* CONFIG_NET_MULTI */
+
+ case 0:
+#ifdef CONFIG_NET_MULTI
+ NetDevExists = 1;
+#endif
+ switch (protocol) {
+ case TFTP:
+ /* always use ARP to get server ethernet address */
+ TftpStart();
+ break;
+
+#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:
+ PingStart();
+ 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
+ default:
+ break;
+ }
+
+ NetBootFileXferSize = 0;
+ break;
+ }
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && defined(CONFIG_STATUS_LED) && defined(STATUS_LED_RED)
+ /*
+ * Echo the inverted link state to the fault LED.
+ */
+ if(miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR)) {
+ status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
+ } else {
+ status_led_set (STATUS_LED_RED, STATUS_LED_ON);
+ }
+#endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
+#endif /* CONFIG_MII, ... */
+
+ /*
+ * Main packet reception loop. Loop receiving packets until
+ * someone sets `NetState' to a state that terminates.
+ */
+ for (;;) {
+ WATCHDOG_RESET();
+#ifdef CONFIG_SHOW_ACTIVITY
+ {
+ extern void show_activity(int arg);
+ 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()) {
+ eth_halt();
+ puts ("\nAbort\n");
+ return (-1);
+ }
+
+ ArpTimeoutCheck();
+
+ /*
+ * Check for a timeout, and run the timeout handler
+ * if we have one.
+ */
+ if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) {
+ thand_f *x;
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+# if defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) && \
+ defined(CONFIG_STATUS_LED) && \
+ defined(STATUS_LED_RED)
+ /*
+ * Echo the inverted link state to the fault LED.
+ */
+ if(miiphy_link(eth_get_dev()->name, CONFIG_SYS_FAULT_MII_ADDR)) {
+ status_led_set (STATUS_LED_RED, STATUS_LED_OFF);
+ } else {
+ status_led_set (STATUS_LED_RED, STATUS_LED_ON);
+ }
+# endif /* CONFIG_SYS_FAULT_ECHO_LINK_DOWN, ... */
+#endif /* CONFIG_MII, ... */
+ x = timeHandler;
+ timeHandler = (thand_f *)0;
+ (*x)();
+ }
+
+
+ switch (NetState) {
+
+ case NETLOOP_RESTART:
+#ifdef CONFIG_NET_MULTI
+ NetRestarted = 1;
+#endif
+ goto restart;
+
+ case NETLOOP_SUCCESS:
+ if (NetBootFileXferSize > 0) {
+ char buf[20];
+ printf("Bytes transferred = %ld (%lx hex)\n",
+ NetBootFileXferSize,
+ NetBootFileXferSize);
+ sprintf(buf, "%lX", NetBootFileXferSize);
+ setenv("filesize", buf);
+
+ sprintf(buf, "%lX", (unsigned long)load_addr);
+ setenv("fileaddr", buf);
+ }
+ eth_halt();
+ return NetBootFileXferSize;
+
+ case NETLOOP_FAIL:
+ return (-1);
+ }
+ }
+}
+
+/**********************************************************************/
+
+static void
+startAgainTimeout(void)
+{
+ NetState = NETLOOP_RESTART;
+}
+
+static void
+startAgainHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len)
+{
+ /* Totally ignore the packet */
+}
+
+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();
+ NetState = NETLOOP_FAIL;
+ return;
+ }
+
+ NetTryCount++;
+
+#ifndef CONFIG_NET_MULTI
+ NetSetTimeout (10000UL, startAgainTimeout);
+ NetSetHandler (startAgainHandler);
+#else /* !CONFIG_NET_MULTI*/
+ 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);
+ NetSetHandler (startAgainHandler);
+ } else {
+ NetState = NETLOOP_FAIL;
+ }
+ } else {
+ NetState = NETLOOP_RESTART;
+ }
+#endif /* CONFIG_NET_MULTI */
+}
+
+/**********************************************************************/
+/*
+ * Miscelaneous bits.
+ */
+
+void
+NetSetHandler(rxhand_f * f)
+{
+ packetHandler = f;
+}
+
+
+void
+NetSetTimeout(ulong iv, thand_f * f)
+{
+ if (iv == 0) {
+ timeHandler = (thand_f *)0;
+ } else {
+ timeHandler = f;
+ timeStart = get_timer(0);
+ timeDelta = iv;
+ }
+}
+
+
+void
+NetSendPacket(volatile uchar * pkt, int len)
+{
+ (void) eth_send(pkt, len);
+}
+
+int
+NetSendUDPPacket(uchar *ether, IPaddr_t dest, int dport, int sport, int len)
+{
+ uchar *pkt;
+
+ /* 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;
+
+ /* if MAC address was not discovered yet, save the packet and do an ARP request */
+ if (memcmp(ether, NetEtherNullAddr, 6) == 0) {
+
+ debug("sending ARP for %08lx\n", dest);
+
+ NetArpWaitPacketIP = dest;
+ NetArpWaitPacketMAC = ether;
+
+ pkt = NetArpWaitTxPacket;
+ pkt += NetSetEther (pkt, NetArpWaitPacketMAC, PROT_IP);
+
+ NetSetIP (pkt, dest, dport, sport, len);
+ memcpy(pkt + IP_HDR_SIZE, (uchar *)NetTxPacket + (pkt - (uchar *)NetArpWaitTxPacket) + IP_HDR_SIZE, len);
+
+ /* size of the waiting packet */
+ NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE + len;
+
+ /* and do the ARP request */
+ NetArpWaitTry = 1;
+ NetArpWaitTimerStart = get_timer(0);
+ ArpRequest();
+ return 1; /* waiting */
+ }
+
+ debug("sending UDP to %08lx/%pM\n", dest, ether);
+
+ pkt = (uchar *)NetTxPacket;
+ pkt += NetSetEther (pkt, ether, PROT_IP);
+ NetSetIP (pkt, dest, dport, sport, len);
+ (void) eth_send(NetTxPacket, (pkt - NetTxPacket) + IP_HDR_SIZE + len);
+
+ return 0; /* transmitted */
+}
+
+#if defined(CONFIG_CMD_PING)
+static ushort PingSeqNo;
+
+int PingSend(void)
+{
+ static uchar mac[6];
+ volatile IP_t *ip;
+ volatile ushort *s;
+ uchar *pkt;
+
+ /* XXX always send arp request */
+
+ memcpy(mac, NetEtherNullAddr, 6);
+
+ debug("sending ARP for %08lx\n", NetPingIP);
+
+ NetArpWaitPacketIP = NetPingIP;
+ NetArpWaitPacketMAC = mac;
+
+ pkt = NetArpWaitTxPacket;
+ pkt += NetSetEther(pkt, mac, PROT_IP);
+
+ ip = (volatile IP_t *)pkt;
+
+ /*
+ * Construct an IP and ICMP header. (need to set no fragment bit - XXX)
+ */
+ ip->ip_hl_v = 0x45; /* IP_HDR_SIZE / 4 (not including UDP) */
+ ip->ip_tos = 0;
+ ip->ip_len = htons(IP_HDR_SIZE_NO_UDP + 8);
+ ip->ip_id = htons(NetIPID++);
+ ip->ip_off = htons(IP_FLAGS_DFRAG); /* Don't fragment */
+ ip->ip_ttl = 255;
+ ip->ip_p = 0x01; /* ICMP */
+ ip->ip_sum = 0;
+ NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
+ NetCopyIP((void*)&ip->ip_dst, &NetPingIP); /* - "" - */
+ ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
+
+ s = &ip->udp_src; /* XXX ICMP starts here */
+ s[0] = htons(0x0800); /* echo-request, code */
+ s[1] = 0; /* checksum */
+ s[2] = 0; /* identifier */
+ s[3] = htons(PingSeqNo++); /* sequence number */
+ s[1] = ~NetCksum((uchar *)s, 8/2);
+
+ /* size of the waiting packet */
+ NetArpWaitTxPacketSize = (pkt - NetArpWaitTxPacket) + IP_HDR_SIZE_NO_UDP + 8;
+
+ /* and do the ARP request */
+ NetArpWaitTry = 1;
+ NetArpWaitTimerStart = get_timer(0);
+ ArpRequest();
+ return 1; /* waiting */
+}
+
+static void
+PingTimeout (void)
+{
+ eth_halt();
+ NetState = NETLOOP_FAIL; /* we did not get the reply */
+}
+
+static void
+PingHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
+{
+ IPaddr_t tmp;
+ volatile IP_t *ip = (volatile IP_t *)pkt;
+
+ tmp = NetReadIP((void *)&ip->ip_src);
+ if (tmp != NetPingIP)
+ return;
+
+ NetState = NETLOOP_SUCCESS;
+}
+
+static void PingStart(void)
+{
+#if defined(CONFIG_NET_MULTI)
+ printf ("Using %s device\n", eth_get_name());
+#endif /* CONFIG_NET_MULTI */
+ NetSetTimeout (10000UL, PingTimeout);
+ NetSetHandler (PingHandler);
+
+ PingSend();
+}
+#endif
+
+#if defined(CONFIG_CMD_CDP)
+
+#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;
+}
+
+int CDPSendTrigger(void)
+{
+ volatile uchar *pkt;
+ volatile ushort *s;
+ volatile ushort *cp;
+ Ethernet_t *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 = (Ethernet_t *)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 = (volatile ushort *)pkt;
+ cp = s;
+ *s++ = htons(0); /* checksum (0 for later calculation) */
+
+ /* 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);
+
+ (void) eth_send(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
+ NetState = NETLOOP_SUCCESS;
+}
+
+static void
+CDPDummyHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
+{
+ /* nothing */
+}
+
+static void
+CDPHandler(const uchar * pkt, unsigned len)
+{
+ const uchar *t;
+ const ushort *ss;
+ ushort type, tlen;
+ uchar applid;
+ 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;
+
+ applid = t[0];
+ ss = (const ushort *)(t + 1);
+
+#ifdef CONFIG_CDP_APPLIANCE_VLAN_TYPE
+ if (applid == CONFIG_CDP_APPLIANCE_VLAN_TYPE)
+ vlan = *ss;
+#else
+ vlan = ntohs(*ss); /* XXX will this work; dunno */
+#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;
+}
+
+static void CDPStart(void)
+{
+#if defined(CONFIG_NET_MULTI)
+ printf ("Using %s device\n", eth_get_name());
+#endif
+ CDPSeq = 0;
+ CDPOK = 0;
+
+ CDPNativeVLAN = htons(-1);
+ CDPApplianceVLAN = htons(-1);
+
+ NetSetTimeout (CDP_TIMEOUT, CDPTimeout);
+ NetSetHandler (CDPDummyHandler);
+
+ CDPSendTrigger();
+}
+#endif
+
+#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_NO_UDP)
+
+/*
+ * 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 IP_t *__NetDefragment(IP_t *ip, int *lenp)
+{
+ static uchar pkt_buff[IP_PKTSIZE] __attribute__((aligned(PKTALIGN)));
+ static u16 first_hole, total_len;
+ struct hole *payload, *thisfrag, *h, *newh;
+ IP_t *localip = (IP_t *)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_NO_UDP);
+ offset8 = (ip_off & IP_OFFS);
+ thisfrag = payload + offset8;
+ start = offset8 * 8;
+ len = ntohs(ip->ip_len) - IP_HDR_SIZE_NO_UDP;
+
+ 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_NO_UDP);
+ }
+
+ /*
+ * 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_NO_UDP, len);
+ if (!done)
+ return NULL;
+
+ localip->ip_len = htons(total_len);
+ *lenp = total_len + IP_HDR_SIZE_NO_UDP;
+ return localip;
+}
+
+static inline IP_t *NetDefragment(IP_t *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 IP_t *NetDefragment(IP_t *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
+
+void
+NetReceive(volatile uchar * inpkt, int len)
+{
+ Ethernet_t *et;
+ IP_t *ip;
+ ARP_t *arp;
+ IPaddr_t tmp;
+ int x;
+ uchar *pkt;
+#if defined(CONFIG_CMD_CDP)
+ int iscdp;
+#endif
+ ushort cti = 0, vlanid = VLAN_NONE, myvlanid, mynvlanid;
+
+ debug("packet received\n");
+
+ NetRxPacket = inpkt;
+ NetRxPacketLen = len;
+ et = (Ethernet_t *)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 = memcmp(et->et_dest, NetCDPAddr, 6) == 0;
+#endif
+
+ myvlanid = ntohs(NetOurVLAN);
+ if (myvlanid == (ushort)-1)
+ myvlanid = VLAN_NONE;
+ mynvlanid = ntohs(NetOurNativeVLAN);
+ if (mynvlanid == (ushort)-1)
+ mynvlanid = VLAN_NONE;
+
+ x = ntohs(et->et_protlen);
+
+ debug("packet received\n");
+
+ if (x < 1514) {
+ /*
+ * Got a 802 packet. Check the other protocol field.
+ */
+ x = ntohs(et->et_prot);
+
+ ip = (IP_t *)(inpkt + E802_HDR_SIZE);
+ len -= E802_HDR_SIZE;
+
+ } else if (x != PROT_VLAN) { /* normal packet */
+ ip = (IP_t *)(inpkt + ETHER_HDR_SIZE);
+ len -= ETHER_HDR_SIZE;
+
+ } else { /* VLAN packet */
+ VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)et;
+
+ debug("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;
+ x = ntohs(vet->vet_type);
+
+ ip = (IP_t *)(inpkt + VLAN_ETHER_HDR_SIZE);
+ len -= VLAN_ETHER_HDR_SIZE;
+ }
+
+ debug("Receive from protocol 0x%x\n", x);
+
+#if defined(CONFIG_CMD_CDP)
+ if (iscdp) {
+ CDPHandler((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 (x) {
+
+ case PROT_ARP:
+ /*
+ * 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("Got ARP\n");
+
+ arp = (ARP_t *)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 != 6) {
+ return;
+ }
+ if (arp->ar_pln != 4) {
+ return;
+ }
+
+ if (NetOurIP == 0) {
+ return;
+ }
+
+ if (NetReadIP(&arp->ar_data[16]) != NetOurIP) {
+ return;
+ }
+
+ switch (ntohs(arp->ar_op)) {
+ case ARPOP_REQUEST: /* reply with our IP address */
+ debug("Got ARP REQUEST, return our IP\n");
+ pkt = (uchar *)et;
+ pkt += NetSetEther(pkt, et->et_src, PROT_ARP);
+ arp->ar_op = htons(ARPOP_REPLY);
+ memcpy (&arp->ar_data[10], &arp->ar_data[0], 6);
+ NetCopyIP(&arp->ar_data[16], &arp->ar_data[6]);
+ memcpy (&arp->ar_data[ 0], NetOurEther, 6);
+ NetCopyIP(&arp->ar_data[ 6], &NetOurIP);
+ (void) eth_send((uchar *)et, (pkt - (uchar *)et) + ARP_HDR_SIZE);
+ return;
+
+ case ARPOP_REPLY: /* arp reply */
+ /* are we waiting for a reply */
+ if (!NetArpWaitPacketIP || !NetArpWaitPacketMAC)
+ break;
+
+#ifdef CONFIG_KEEP_SERVERADDR
+ if (NetServerIP == NetArpWaitPacketIP) {
+ char buf[20];
+ sprintf(buf, "%pM", arp->ar_data);
+ setenv("serveraddr", buf);
+ }
+#endif
+
+ debug("Got ARP REPLY, set server/gtwy eth addr (%pM)\n",
+ arp->ar_data);
+
+ tmp = NetReadIP(&arp->ar_data[6]);
+
+ /* matched waiting packet's address */
+ if (tmp == NetArpWaitReplyIP) {
+ debug("Got it\n");
+ /* save address for later use */
+ memcpy(NetArpWaitPacketMAC, &arp->ar_data[0], 6);
+
+#ifdef CONFIG_NETCONSOLE
+ (*packetHandler)(0,0,0,0);
+#endif
+ /* modify header, and transmit it */
+ memcpy(((Ethernet_t *)NetArpWaitTxPacket)->et_dest, NetArpWaitPacketMAC, 6);
+ (void) eth_send(NetArpWaitTxPacket, 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));
+ return;
+ }
+ break;
+
+#ifdef CONFIG_CMD_RARP
+ case PROT_RARP:
+ debug("Got RARP\n");
+ arp = (ARP_t *)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);
+
+ (*packetHandler)(0,0,0,0);
+ }
+ break;
+#endif
+ case PROT_IP:
+ debug("Got IP\n");
+ /* Before we start poking the header, make sure it is there */
+ if (len < IP_HDR_SIZE) {
+ debug("len bad %d < %lu\n", len, (ulong)IP_HDR_SIZE);
+ return;
+ }
+ /* Check the packet length */
+ if (len < ntohs(ip->ip_len)) {
+ printf("len bad %d < %d\n", len, ntohs(ip->ip_len));
+ return;
+ }
+ len = ntohs(ip->ip_len);
+ debug("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_NO_UDP / 2)) {
+ puts ("checksum bad\n");
+ return;
+ }
+ /* If it is not for us, ignore it */
+ tmp = NetReadIP(&ip->ip_dst);
+ if (NetOurIP && tmp != NetOurIP && tmp != 0xFFFFFFFF) {
+#ifdef CONFIG_MCAST_TFTP
+ if (Mcast_addr != tmp)
+#endif
+ return;
+ }
+ /*
+ * 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)
+ */
+ if (!(ip = NetDefragment(ip, &len)))
+ 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.
+ */
+ if (ip->ip_p == IPPROTO_ICMP) {
+ ICMP_t *icmph = (ICMP_t *)&(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);
+ return;
+#if defined(CONFIG_CMD_PING)
+ case ICMP_ECHO_REPLY:
+ /*
+ * IP header OK. Pass the packet to the current handler.
+ */
+ /* XXX point to ip packet */
+ (*packetHandler)((uchar *)ip, 0, 0, 0);
+ return;
+ case ICMP_ECHO_REQUEST:
+ debug("Got ICMP ECHO REQUEST, return %d bytes \n",
+ ETHER_HDR_SIZE + len);
+
+ memcpy (&et->et_dest[0], &et->et_src[0], 6);
+ memcpy (&et->et_src[ 0], NetOurEther, 6);
+
+ 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_NO_UDP >> 1);
+
+ icmph->type = ICMP_ECHO_REPLY;
+ icmph->checksum = 0;
+ icmph->checksum = ~NetCksum((uchar *)icmph,
+ (len - IP_HDR_SIZE_NO_UDP) >> 1);
+ (void) eth_send((uchar *)et, ETHER_HDR_SIZE + len);
+ return;
+#endif
+ default:
+ return;
+ }
+ } else if (ip->ip_p != IPPROTO_UDP) { /* Only UDP packets */
+ return;
+ }
+
+#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_HDR_SIZE,
+ ntohs(ip->udp_dst),
+ ntohs(ip->udp_src),
+ ntohs(ip->udp_len) - 8);
+#endif
+ /*
+ * IP header OK. Pass the packet to the current handler.
+ */
+ (*packetHandler)((uchar *)ip +IP_HDR_SIZE,
+ ntohs(ip->udp_dst),
+ ntohs(ip->udp_src),
+ ntohs(ip->udp_len) - 8);
+ break;
+ }
+}
+
+
+/**********************************************************************/
+
+static int net_check_prereq (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 NETCONS:
+ case TFTP:
+ if (NetServerIP == 0) {
+ puts ("*** ERROR: `serverip' not set\n");
+ return (1);
+ }
+#if defined(CONFIG_CMD_PING) || defined(CONFIG_CMD_SNTP)
+ common:
+#endif
+
+ 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:
+ if (memcmp (NetOurEther, "\0\0\0\0\0\0", 6) == 0) {
+#ifdef CONFIG_NET_MULTI
+ extern int eth_get_dev_index (void);
+ 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);
+#else
+ puts ("*** ERROR: `ethaddr' not set\n");
+ return (1);
+#endif
+ }
+ /* 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(volatile uchar * xet, uchar * addr, uint prot)
+{
+ Ethernet_t *et = (Ethernet_t *)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 {
+ VLAN_Ethernet_t *vet = (VLAN_Ethernet_t *)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;
+ }
+}
+
+void
+NetSetIP(volatile uchar * xip, IPaddr_t dest, int dport, int sport, int len)
+{
+ IP_t *ip = (IP_t *)xip;
+
+ /*
+ * 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)
+ xip[IP_HDR_SIZE + len] = 0;
+
+ /*
+ * Construct an IP and UDP header.
+ * (need to set no fragment bit - XXX)
+ */
+ ip->ip_hl_v = 0x45; /* IP_HDR_SIZE / 4 (not including UDP) */
+ ip->ip_tos = 0;
+ ip->ip_len = htons(IP_HDR_SIZE + len);
+ ip->ip_id = htons(NetIPID++);
+ ip->ip_off = htons(IP_FLAGS_DFRAG); /* Don't fragment */
+ ip->ip_ttl = 255;
+ ip->ip_p = 17; /* UDP */
+ ip->ip_sum = 0;
+ NetCopyIP((void*)&ip->ip_src, &NetOurIP); /* already in network byte order */
+ NetCopyIP((void*)&ip->ip_dst, &dest); /* - "" - */
+ ip->udp_src = htons(sport);
+ ip->udp_dst = htons(dport);
+ ip->udp_len = htons(8 + len);
+ ip->udp_xsum = 0;
+ ip->ip_sum = ~NetCksum((uchar *)ip, IP_HDR_SIZE_NO_UDP / 2);
+}
+
+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/u-boot/net/nfs.c b/u-boot/net/nfs.c
new file mode 100644
index 0000000..d11bb4c
--- /dev/null
+++ b/u-boot/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
+#define NFS_TIMEOUT 2000UL
+
+static int fs_mounted = 0;
+static unsigned long rpc_id = 0;
+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 int NfsDownloadState;
+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_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, 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");
+ NetState = NETLOOP_FAIL;
+ } else {
+ puts ("\ndone\n");
+ NetState = NfsDownloadState;
+ }
+ 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 ) NfsDownloadState = NETLOOP_SUCCESS;
+ NfsState = STATE_UMOUNT_REQ;
+ NfsSend ();
+ }
+ break;
+ }
+}
+
+
+void
+NfsStart (void)
+{
+ debug("%s\n", __func__);
+ NfsDownloadState = NETLOOP_FAIL;
+
+ NfsServerIP = NetServerIP;
+ nfs_path = (char *)nfs_path_buff;
+
+ if (nfs_path == NULL) {
+ NetState = NETLOOP_FAIL;
+ puts ("*** ERROR: Fail allocate memory\n");
+ return;
+ }
+
+ if (BootFile[0] == '\0') {
+ sprintf (default_filename, "/nfsroot/%02lX%02lX%02lX%02lX.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);
+
+#if defined(CONFIG_NET_MULTI)
+ printf ("Using %s device\n", eth_get_name());
+#endif
+
+ 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);
+ NetSetHandler (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/u-boot/net/nfs.h b/u-boot/net/nfs.h
new file mode 100644
index 0000000..de8a0c6
--- /dev/null
+++ b/u-boot/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/u-boot/net/rarp.c b/u-boot/net/rarp.c
new file mode 100644
index 0000000..9444c03
--- /dev/null
+++ b/u-boot/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.
+ */
+static void
+RarpHandler(uchar * dummi0, unsigned dummi1, unsigned dummi2, unsigned dummi3)
+{
+ char *s;
+ debug("Got good RARP\n");
+ if ((s = getenv("autoload")) != NULL) {
+ if (*s == 'n') {
+ /*
+ * Just use RARP to configure system;
+ * Do not use TFTP/NFS to to load the bootfile.
+ */
+ NetState = NETLOOP_SUCCESS;
+ return;
+#if defined(CONFIG_CMD_NFS)
+ } else if ((s != NULL) && !strcmp(s, "NFS")) {
+ NfsStart();
+ return;
+#endif
+ }
+ }
+ TftpStart ();
+}
+
+
+/*
+ * 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)
+{
+ int i;
+ volatile uchar *pkt;
+ ARP_t * rarp;
+
+ printf("RARP broadcast %d\n", ++RarpTry);
+ pkt = NetTxPacket;
+
+ pkt += NetSetEther(pkt, NetBcastAddr, PROT_RARP);
+
+ rarp = (ARP_t *)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 */
+ memcpy (&rarp->ar_data[10], NetOurEther, 6); /* dest ET addr = source ET addr ??*/
+ /* dest. IP addr set to broadcast */
+ for (i = 0; i <= 3; i++) {
+ rarp->ar_data[16 + i] = 0xff;
+ }
+
+ NetSendPacket(NetTxPacket, (pkt - NetTxPacket) + ARP_HDR_SIZE);
+
+ NetSetTimeout(TIMEOUT, RarpTimeout);
+ NetSetHandler(RarpHandler);
+}
diff --git a/u-boot/net/rarp.h b/u-boot/net/rarp.h
new file mode 100644
index 0000000..0c16d46
--- /dev/null
+++ b/u-boot/net/rarp.h
@@ -0,0 +1,44 @@
+/*
+ * (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
+ */
+
+
+#ifndef __RARP_H__
+#define __RARP_H__
+
+#ifndef __NET_H__
+#include <net.h>
+#endif /* __NET_H__ */
+
+
+/**********************************************************************/
+/*
+ * Global functions and variables.
+ */
+
+extern int RarpTry;
+
+extern void RarpRequest (void); /* Send a RARP request */
+
+/**********************************************************************/
+
+#endif /* __RARP_H__ */
diff --git a/u-boot/net/sntp.c b/u-boot/net/sntp.c
new file mode 100644
index 0000000..76c10ec
--- /dev/null
+++ b/u-boot/net/sntp.c
@@ -0,0 +1,88 @@
+/*
+ * 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_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");
+ NetState = NETLOOP_FAIL;
+ return;
+}
+
+static void
+SntpHandler (uchar *pkt, unsigned dest, 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);
+
+ NetState = NETLOOP_SUCCESS;
+}
+
+void
+SntpStart (void)
+{
+ debug("%s\n", __func__);
+
+ NetSetTimeout (SNTP_TIMEOUT, SntpTimeout);
+ NetSetHandler(SntpHandler);
+ memset (NetServerEther, 0, 6);
+
+ SntpSend ();
+}
diff --git a/u-boot/net/sntp.h b/u-boot/net/sntp.h
new file mode 100644
index 0000000..8a097bf
--- /dev/null
+++ b/u-boot/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/u-boot/net/tftp.c b/u-boot/net/tftp.c
new file mode 100644
index 0000000..ed559b7
--- /dev/null
+++ b/u-boot/net/tftp.c
@@ -0,0 +1,729 @@
+/*
+ * Copyright 1994, 1995, 2000 Neil Russell.
+ * (See License)
+ * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include "tftp.h"
+#include "bootp.h"
+
+#define WELL_KNOWN_PORT 69 /* Well known TFTP port # */
+#define TIMEOUT 5000UL /* Millisecs to timeout for lost pkt */
+#ifndef CONFIG_NET_RETRY_COUNT
+# define TIMEOUT_COUNT 10 /* # of timeouts before giving up */
+#else
+# define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT * 2)
+#endif
+ /* (for checking the image size) */
+#define HASHES_PER_LINE 65 /* Number of "loading" hashes per line */
+
+/*
+ * 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;
+
+/*
+ * 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 TftpServerIP;
+static int TftpServerPort; /* The UDP port at their end */
+static int TftpOurPort; /* The UDP port at our end */
+static int TftpTimeoutCount;
+static ulong TftpBlock; /* packet sequence number */
+static ulong TftpLastBlock; /* last packet sequence number received */
+static ulong TftpBlockWrap; /* count of sequence number wraparounds */
+static ulong TftpBlockWrapOffset; /* memory offset due to wrapping */
+static int TftpState;
+#ifdef CONFIG_TFTP_TSIZE
+static int TftpTsize; /* The file size reported by the server */
+static short TftpNumchars; /* The number of hashes we printed */
+#endif
+
+#define STATE_RRQ 1
+#define STATE_DATA 2
+#define STATE_TOO_LARGE 3
+#define STATE_BAD_MAGIC 4
+#define STATE_OACK 5
+
+#define TFTP_BLOCK_SIZE 512 /* default TFTP block size */
+#define TFTP_SEQUENCE_SIZE ((ulong)(1<<16)) /* sequence number is 16 bit */
+
+#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];
+
+#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP
+extern flash_info_t flash_info[];
+#endif
+
+/* 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;
+
+#ifdef CONFIG_MCAST_TFTP
+#include <malloc.h>
+#define MTFTP_BITMAPSIZE 0x1000
+static unsigned *Bitmap;
+static int PrevBitmapHole,Mapsize=MTFTP_BITMAPSIZE;
+static uchar ProhibitMcast=0, MasterClient=0;
+static uchar Multicast=0;
+extern IPaddr_t Mcast_addr;
+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 (unsigned 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);
+ NetState = 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;
+}
+
+static void TftpSend (void);
+static void TftpTimeout (void);
+
+/**********************************************************************/
+
+static void
+TftpSend (void)
+{
+ volatile uchar * pkt;
+ volatile uchar * xp;
+ int len = 0;
+ volatile 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_HDR_SIZE;
+
+ switch (TftpState) {
+
+ case STATE_RRQ:
+ xp = pkt;
+ s = (ushort *)pkt;
+ *s++ = htons(TFTP_RRQ);
+ 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
+ memcpy((char *)pkt, "tsize\0000\0", 8);
+ pkt += 8;
+#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))
+ && 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_DATA:
+ xp = pkt;
+ s = (ushort *)pkt;
+ *s++ = htons(TFTP_ACK);
+ *s++ = htons(TftpBlock);
+ pkt = (uchar *)s;
+ 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, TftpServerIP, TftpServerPort, TftpOurPort, len);
+}
+
+
+static void
+TftpHandler (uchar * pkt, unsigned dest, 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_RRQ && src != TftpServerPort) {
+ 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:
+ case TFTP_WRQ:
+ case TFTP_ACK:
+ break;
+ default:
+ break;
+
+ case TFTP_OACK:
+ debug("Got OACK: %s %s\n",
+ pkt,
+ pkt + strlen((char *)pkt) + 1);
+ TftpState = STATE_OACK;
+ TftpServerPort = 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
+ TftpSend (); /* Send ACK */
+ break;
+ case TFTP_DATA:
+ if (len < 2)
+ return;
+ len -= 2;
+ TftpBlock = ntohs(*(ushort *)pkt);
+
+ /*
+ * 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;
+ printf ("\n\t %lu MB received\n\t ", TftpBlockWrapOffset>>20);
+ }
+#ifdef CONFIG_TFTP_TSIZE
+ else if (TftpTsize) {
+ while (TftpNumchars < NetBootFileXferSize * 50 / TftpTsize) {
+ putc('#');
+ TftpNumchars++;
+ }
+ }
+#endif
+ else {
+ if (((TftpBlock - 1) % 10) == 0) {
+ putc ('#');
+ } else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) {
+ puts ("\n\t ");
+ }
+ }
+
+ if (TftpState == STATE_RRQ)
+ debug("Server did not acknowledge timeout option!\n");
+
+ if (TftpState == STATE_RRQ || TftpState == STATE_OACK) {
+ /* first block received */
+ TftpState = STATE_DATA;
+ TftpServerPort = src;
+ TftpLastBlock = 0;
+ TftpBlockWrap = 0;
+ TftpBlockWrapOffset = 0;
+
+#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);
+
+ /*
+ * Acknoledge the block just received, which will prompt
+ * the server 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();
+ NetState = NETLOOP_SUCCESS;
+ }
+ }
+ else
+#endif
+ if (len < TftpBlkSize) {
+ /*
+ * We received the whole thing. Try to
+ * run it.
+ */
+#ifdef CONFIG_TFTP_TSIZE
+ /* Print out the hash marks for the last packet received */
+ while (TftpTsize && TftpNumchars < 49) {
+ putc('#');
+ TftpNumchars++;
+ }
+#endif
+ puts ("\ndone\n");
+ NetState = NETLOOP_SUCCESS;
+ }
+ 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();
+ NetState = 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 void
+TftpTimeout (void)
+{
+ if (++TftpTimeoutCount > TftpTimeoutCountMax) {
+ puts ("\nRetry count exceeded; starting again\n");
+#ifdef CONFIG_MCAST_TFTP
+ mcast_cleanup();
+#endif
+ NetStartAgain ();
+ } else {
+ puts ("T ");
+ NetSetTimeout (TftpTimeoutMSecs, TftpTimeout);
+ TftpSend ();
+ }
+}
+
+
+void
+TftpStart (void)
+{
+ char *ep; /* Environment pointer */
+
+ /*
+ * Allow the user to choose TFTP blocksize and timeout.
+ * TFTP protocol has a minimal timeout of 1 second.
+ */
+ if ((ep = getenv("tftpblocksize")) != NULL)
+ TftpBlkSizeOption = simple_strtol(ep, NULL, 10);
+
+ if ((ep = getenv("tftptimeout")) != 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);
+
+ TftpServerIP = NetServerIP;
+ if (BootFile[0] == '\0') {
+ sprintf(default_filename, "%02lX%02lX%02lX%02lX.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);
+ tftp_filename[MAX_LEN-1] = 0;
+ } else {
+ TftpServerIP = string_to_ip (BootFile);
+ strncpy(tftp_filename, p + 1, MAX_LEN);
+ tftp_filename[MAX_LEN-1] = 0;
+ }
+ }
+
+#if defined(CONFIG_NET_MULTI)
+ printf ("Using %s device\n", eth_get_name());
+#endif
+ printf("TFTP from server %pI4"
+ "; our IP address is %pI4", &TftpServerIP, &NetOurIP);
+
+ /* Check if we need to send across this subnet */
+ if (NetOurGatewayIP && NetOurSubnetMask) {
+ IPaddr_t OurNet = NetOurIP & NetOurSubnetMask;
+ IPaddr_t ServerNet = TftpServerIP & NetOurSubnetMask;
+
+ if (OurNet != ServerNet)
+ 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');
+
+ printf ("Load address: 0x%lx\n", load_addr);
+
+ puts ("Loading: *\b");
+
+ TftpTimeoutCountMax = TftpRRQTimeoutCountMax;
+
+ NetSetTimeout (TftpTimeoutMSecs, TftpTimeout);
+ NetSetHandler (TftpHandler);
+
+ TftpServerPort = WELL_KNOWN_PORT;
+ TftpTimeoutCount = 0;
+ TftpState = STATE_RRQ;
+ /* Use a pseudo-random port unless a specific port is set */
+ TftpOurPort = 1024 + (get_timer(0) % 3072);
+
+#ifdef CONFIG_TFTP_PORT
+ if ((ep = getenv("tftpdstp")) != NULL) {
+ TftpServerPort = simple_strtol(ep, NULL, 10);
+ }
+ if ((ep = getenv("tftpsrcp")) != 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 ();
+}
+
+#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
+ */
+ if (!(Bitmap = malloc (Mapsize))) {
+ 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);
+ if (eth_mcast_join(Mcast_addr=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/u-boot/net/tftp.h b/u-boot/net/tftp.h
new file mode 100644
index 0000000..e3dfb26
--- /dev/null
+++ b/u-boot/net/tftp.h
@@ -0,0 +1,21 @@
+/*
+ * LiMon - BOOTP/TFTP.
+ *
+ * Copyright 1994, 1995, 2000 Neil Russell.
+ * (See License)
+ */
+
+#ifndef __TFTP_H__
+#define __TFTP_H__
+
+/**********************************************************************/
+/*
+ * Global functions and variables.
+ */
+
+/* tftp.c */
+extern void TftpStart (void); /* Begin TFTP get */
+
+/**********************************************************************/
+
+#endif /* __TFTP_H__ */