Skip to content
Snippets Groups Projects
net.c 38.1 KiB
Newer Older
Wolfgang Denk's avatar
Wolfgang Denk committed
/*
 *	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:
 *
Wolfgang Denk's avatar
Wolfgang Denk committed
 *     Prerequisites:	- own ethernet address
 *     We want:		- IP, Netmask, ServerIP, Gateway IP
 *			- bootfilename, lease time
 *     Next step:	- TFTP
Wolfgang Denk's avatar
Wolfgang Denk committed
 *
 * 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
Wolfgang Denk's avatar
Wolfgang Denk committed
 *	Prerequisites:	- own ethernet address
 *			- own IP address
 *	We want:	- network time
 *	Next step:	none
Wolfgang Denk's avatar
Wolfgang Denk committed
 */


#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_CDP_VERSION)
#include <timestamp.h>
#endif
Wolfgang Denk's avatar
Wolfgang Denk committed

#if defined(CONFIG_CMD_NET)
Wolfgang Denk's avatar
Wolfgang Denk committed

#ifndef	CONFIG_ARP_TIMEOUT
# define ARP_TIMEOUT		5000UL	/* Milliseconds before trying ARP again */
# define ARP_TIMEOUT		CONFIG_ARP_TIMEOUT
#ifndef	CONFIG_NET_RETRY_COUNT
# define ARP_TIMEOUT_COUNT	5	/* # of timeouts before giving up  */
#else
# define ARP_TIMEOUT_COUNT	CONFIG_NET_RETRY_COUNT
Wolfgang Denk's avatar
Wolfgang Denk committed
#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
Wolfgang Denk's avatar
Wolfgang Denk committed
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	*/

David Updegraff's avatar
David Updegraff committed
#ifdef CONFIG_MCAST_TFTP	/* Multicast TFTP */
IPaddr_t Mcast_addr;
#endif

Wolfgang Denk's avatar
Wolfgang Denk committed
/** 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 };
Wolfgang Denk's avatar
Wolfgang Denk committed
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		*/
Wolfgang Denk's avatar
Wolfgang Denk committed
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)
Wolfgang Denk's avatar
Wolfgang Denk committed
uchar		NetCDPAddr[6] =		/* Ethernet bcast address		*/
			{ 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc };
#endif
Wolfgang Denk's avatar
Wolfgang Denk committed
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

Wolfgang Denk's avatar
Wolfgang Denk committed
/* XXX in both little & big endian machines 0xFFFF == ntohs(-1) */
ushort		NetOurVLAN = 0xFFFF;		/* default is without VLAN	*/
ushort		NetOurNativeVLAN = 0xFFFF;	/* ditto			*/
Wolfgang Denk's avatar
Wolfgang Denk committed
char		BootFile[128];		/* Boot File name			*/

#if defined(CONFIG_CMD_PING)
Wolfgang Denk's avatar
Wolfgang Denk committed
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

Wolfgang Denk's avatar
Wolfgang Denk committed
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		*/
Wolfgang Denk's avatar
Wolfgang Denk committed
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	*/
Wolfgang Denk's avatar
Wolfgang Denk committed
uchar	       *NetArpWaitTxPacket;	/* THE transmit packet			*/
int		NetArpWaitTxPacketSize;
Wolfgang Denk's avatar
Wolfgang Denk committed
uchar		NetArpWaitPacketBuf[PKTSIZE_ALIGN + PKTALIGN];
ulong		NetArpWaitTimerStart;
int		NetArpWaitTry;

Wolfgang Denk's avatar
Wolfgang Denk committed
void ArpRequest (void)
{
	int i;
	volatile uchar *pkt;
Wolfgang Denk's avatar
Wolfgang Denk committed
	ARP_t *arp;

#ifdef ET_DEBUG
Wolfgang Denk's avatar
Wolfgang Denk committed
	printf ("ARP broadcast %d\n", NetArpWaitTry);
#endif
	pkt = NetTxPacket;

Wolfgang Denk's avatar
Wolfgang Denk committed
	pkt += NetSetEther (pkt, NetBcastAddr, PROT_ARP);
Wolfgang Denk's avatar
Wolfgang Denk committed
	arp = (ARP_t *) pkt;
Wolfgang Denk's avatar
Wolfgang Denk committed
	arp->ar_hrd = htons (ARP_ETHER);
	arp->ar_pro = htons (PROT_IP);
	arp->ar_hln = 6;
	arp->ar_pln = 4;
Wolfgang Denk's avatar
Wolfgang Denk committed
	arp->ar_op = htons (ARPOP_REQUEST);
Wolfgang Denk's avatar
Wolfgang Denk committed
	memcpy (&arp->ar_data[0], NetOurEther, 6);		/* source ET addr	*/
	NetWriteIP ((uchar *) & arp->ar_data[6], NetOurIP);	/* source IP addr	*/
Wolfgang Denk's avatar
Wolfgang Denk committed
	for (i = 10; i < 16; ++i) {
		arp->ar_data[i] = 0;				/* dest ET addr = 0     */
Wolfgang Denk's avatar
Wolfgang Denk committed
	if ((NetArpWaitPacketIP & NetOurSubnetMask) !=
	    (NetOurIP & NetOurSubnetMask)) {
		if (NetOurGatewayIP == 0) {
			puts ("## Warning: gatewayip needed but not set\n");
			NetArpWaitReplyIP = NetArpWaitPacketIP;
		} else {
			NetArpWaitReplyIP = NetOurGatewayIP;
Wolfgang Denk's avatar
Wolfgang Denk committed
		}
	} else {
		NetArpWaitReplyIP = NetArpWaitPacketIP;
	}
Wolfgang Denk's avatar
Wolfgang Denk committed
	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");
		env_changed_id = env_id;
	return;
Wolfgang Denk's avatar
Wolfgang Denk committed
/**********************************************************************/
/*
 *	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;

Wolfgang Denk's avatar
Wolfgang Denk committed
	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;
Wolfgang Denk's avatar
Wolfgang Denk committed
	}

	eth_halt();
Wolfgang Denk's avatar
Wolfgang Denk committed
#ifdef CONFIG_NET_MULTI
	eth_set_current();
Wolfgang Denk's avatar
Wolfgang Denk committed
#endif
	if (eth_init(bd) < 0) {
		eth_halt();
Wolfgang Denk's avatar
Wolfgang Denk committed
		return(-1);
Wolfgang Denk's avatar
Wolfgang Denk committed

restart:
#ifdef CONFIG_NET_MULTI
	memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
#else
	eth_getenv_enetaddr("ethaddr", NetOurEther);
Wolfgang Denk's avatar
Wolfgang Denk committed
#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);
Wolfgang Denk's avatar
Wolfgang Denk committed

	switch (net_check_prereq (protocol)) {
	case 1:
		/* network not configured */
		return (-1);
Wolfgang Denk's avatar
Wolfgang Denk committed

#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();
Wolfgang Denk's avatar
Wolfgang Denk committed
			break;

#if defined(CONFIG_CMD_DHCP)
Wolfgang Denk's avatar
Wolfgang Denk committed
		case DHCP:
			BootpTry = 0;
Wolfgang Denk's avatar
Wolfgang Denk committed
			DhcpRequest();		/* Basically same as BOOTP */
			break;
Wolfgang Denk's avatar
Wolfgang Denk committed

		case BOOTP:
			BootpTry = 0;
			BootpRequest ();
			break;

		case RARP:
			RarpTry = 0;
			RarpRequest ();
			break;
#if defined(CONFIG_CMD_PING)
		case PING:
			PingStart();
			break;
#if defined(CONFIG_CMD_NFS)
		case NFS:
			NfsStart();
			break;
#if defined(CONFIG_CMD_CDP)
		case CDP:
			CDPStart();
			break;
#endif
#ifdef CONFIG_NETCONSOLE
		case NETCONS:
			NcStart();
			break;
#if defined(CONFIG_CMD_SNTP)
		case SNTP:
			SntpStart();
			break;
#endif
Wolfgang Denk's avatar
Wolfgang Denk committed
		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, ... */
Wolfgang Denk's avatar
Wolfgang Denk committed

	/*
	 *	Main packet reception loop.  Loop receiving packets until
Wolfgang Denk's avatar
Wolfgang Denk committed
	 *	someone sets `NetState' to a state that terminates.
Wolfgang Denk's avatar
Wolfgang Denk committed
	 */
	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.
		 */
Wolfgang Denk's avatar
Wolfgang Denk committed

		/*
		 *	Abort if ctrl-c was pressed.
		 */
		if (ctrlc()) {
Wolfgang Denk's avatar
Wolfgang Denk committed
			eth_halt();
			puts ("\nAbort\n");
			return (-1);
Wolfgang Denk's avatar
Wolfgang Denk committed
		}

		ArpTimeoutCheck();
Wolfgang Denk's avatar
Wolfgang Denk committed

		/*
		 *	Check for a timeout, and run the timeout handler
		 *	if we have one.
		 */
		if (timeHandler && ((get_timer(0) - timeStart) > timeDelta)) {
Wolfgang Denk's avatar
Wolfgang Denk committed
			thand_f *x;

Jon Loeliger's avatar
Loading
Loading full blame...