/*
* 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"
#include "rarp.h"
#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_CMD_NET)
DECLARE_GLOBAL_DATA_PTR;
#define ARP_TIMEOUT 5 /* Seconds before trying ARP again */
#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
#if 0
#define ET_DEBUG
#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; /* Our IP addr (0 = unknown) */
volatile uchar *NetRxPkt; /* Current receive packet */
int NetRxPktLen; /* 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 };
#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);
/**********************************************************************/
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;
#ifdef ET_DEBUG
printf ("ARP broadcast %d\n", NetArpWaitTry);
#endif
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 * CFG_HZ) {
NetArpWaitTry++;
if (NetArpWaitTry >= ARP_TIMEOUT_COUNT) {
puts ("\nARP Retry count exceeded; starting again\n");
NetArpWaitTry = 0;
NetStartAgain();
} else {
NetArpWaitTimerStart = t;
ArpRequest();
}
}
}
/**********************************************************************/
/*
* 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;
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
memcpy (NetOurEther, bd->bi_enetaddr, 6);
#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.
*/
switch (protocol) {
#if defined(CONFIG_CMD_NFS)
case NFS:
#endif
#if defined(CONFIG_CMD_PING)
case PING:
#endif
#if defined(CONFIG_CMD_SNTP)
case SNTP:
#endif
case NETCONS:
case TFTP:
NetCopyIP(&NetOurIP, &bd->bi_ip_addr);
NetOurGatewayIP = getenv_IPaddr ("gatewayip");
NetOurSubnetMask= getenv_IPaddr ("netmask");
NetOurVLAN = getenv_VLAN("vlan");
NetOurNativeVLAN = getenv_VLAN("nvlan");
switch (protocol) {
#if defined(CONFIG_CMD_NFS)
case NFS:
#endif
case NETCONS:
case TFTP:
NetServerIP = getenv_IPaddr ("serverip");
break;
#if defined(CONFIG_CMD_PING)
case PING:
/* nothing */
break;
#endif
#if defined(CONFIG_CMD_SNTP)
case SNTP:
/* nothing */
break;
#endif
default:
break;
}
break;
case BOOTP:
case RARP:
/*
* initialize our IP addr to 0 in order to accept ANY
* IP addr assigned to us by the BOOTP / RARP server
*/
NetOurIP = 0;
NetServerIP = getenv_IPaddr ("serverip");
NetOurVLAN = getenv_VLAN("vlan"); /* VLANs must be read */
NetOurNativeVLAN = getenv_VLAN("nvlan");
case CDP:
|