⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ethernet.c

📁 umon bootloader source code, support mips cpu.
💻 C
📖 第 1 页 / 共 3 页
字号:
/* ethernet.c:
 *	This code supports most of the generic ethernet/IP/ARP/UDP stuff.
 *
 *	General notice:
 *	This code is part of a boot-monitor package developed as a generic base
 *	platform for embedded system designs.  As such, it is likely to be
 *	distributed to various projects beyond the control of the original
 *	author.  Please notify the author of any enhancements made or bugs found
 *	so that all may benefit from the changes.  In addition, notification back
 *	to the author will allow the new user to pick up changes that may have
 *	been made by other users after this version of the code was distributed.
 *
 *	Note1: the majority of this code was edited with 4-space tabs.
 *	Note2: as more and more contributions are accepted, the term "author"
 *		   is becoming a mis-representation of credit.
 *
 *	Original author:	Ed Sutter
 *	Email:				esutter@lucent.com
 *	Phone:				908-582-2351
 */
#include "config.h"
#include "endian.h"
#include "stddefs.h"
#include "genlib.h"

#if INCLUDE_ETHERNET
#include "cpuio.h"
#include "ether.h"
#include "monflags.h"
#include "cli.h"

void ShowEthernetStats(void);
void executeMONCMD(void);
void processMONCMD(struct ether_header *,ushort);
int  SendIPMonChar(uchar,int);
char IPMonCmdLine[CMDLINESIZE];
int  IPMonCmdVerbose;

#if INCLUDE_DHCPBOOT
#define dhcpStateCheck()	dhcpStateCheck()
#define	dhcpDisable()		dhcpDisable()
#define	ShowDhcpStats()		ShowDhcpStats()
#else
#define dhcpStateCheck()
#define	dhcpDisable()
#define	ShowDhcpStats()
#endif

#if INCLUDE_TFTP
#define	tftpStateCheck()	tftpStateCheck()
#define	tftpInit()			tftpInit()
#define	ShowTftpStats()		ShowTftpStats()
#else
#define	tftpStateCheck()
#define	tftpInit()
#define	ShowTftpStats()
#endif


char *Etheradd, *IPadd;		/* Pointers to ascii addresses */
uchar BinIpAddr[4];			/* Space for binary IP address */
uchar BinEnetAddr[6];		/* Space for binary MAC address */
int EtherVerbose;			/* Verbosity flag (see ether.h). */
int EtherIsActive;			/* Non-zero if ethernet is up. */
int	EtherIPERRCnt;			/* Number of IP errors detected. */
int	EtherUDPERRCnt;			/* Number of UDP errors detected. */
int	EtherXFRAMECnt;			/* Number of packets transmitted. */
int	EtherRFRAMECnt;			/* Number of packets received. */
int	EtherPollNesting;		/* Incremented when pollethernet() is called. */
int	MaxEtherPollNesting;	/* High-warter mark of EtherPollNesting. */
int	IPMonCmdActive;			/* Set if MONCMD is in progress. */
ushort	UniqueIpId;
ulong IPMonCmdHdrBuf[(sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct Udphdr) + 128)/(sizeof(ulong))];
struct	ether_header *IPMonCmdHdr;

/* AppPktPtr & AppPktLen:
 * These two values are used to allow the monitor's ethernet driver
 * to easily (not necessarily most efficiently) hook up to an application
 * that needs to be able to send and/or receive ethernet packets.
 * Refer to discussion above monRecvEnetPkt().
 */
char *AppPktPtr;
int	AppPktLen;

/* Ports used by the monitor have defaults, but can be redefined using
 * shell variables:
 */
ushort	MoncmdPort;			/* shell var: MCMDPORT */
ushort	GdbPort;			/* shell var: GDBPORT */
ushort	DhcpClientPort;		/* shell var: DCLIPORT */
ushort	DhcpServerPort;		/* shell var: DSRVPORT */
ushort	TftpPort;			/* shell var: TFTPPORT */
ushort	TftpSrcPort;		/* shell var: TFTPPORT */

uchar BroadcastAddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
uchar AllZeroAddr[]   = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

struct	pinfo {
	int	pnum;
	char	*pname;
} protocols[] = {
		{ IP_IP,		"IP" },
		{ IP_ICMP,		"ICMP" },
		{ IP_IGMP,		"IGMP" },
		{ IP_GGP,		"GGP" },
		{ IP_TCP,		"TCP" },
		{ IP_PUP,		"PUP" },
		{ IP_UDP,		"UDP" },
		{ 0,0 },
};

struct enet_verbosity {
	char	letter;
	ulong	flags;
} enet_verbose_tbl[] = {
	{ '0',	0 },
	{ 'a',	SHOW_ARP | SHOW_BROADCAST },
	{ 'c',	SHOW_BADCSUM },
	{ 'C',	SHOW_BADCSUM | SHOW_BADCSUMV },
	{ 'd',	SHOW_DHCP },
#if INCLUDE_GDB
	{ 'g',	SHOW_GDB },
#endif
	{ 'i',	SHOW_INCOMING },
	{ 'I',	SHOW_INCOMING | SHOW_BROADCAST },
	{ 'o',	SHOW_OUTGOING },
	{ 'p',	SHOW_PHY },
	{ 't',	SHOW_TFTP_STATE },
	{ 'x',	SHOW_HEX },
	{ 'X',	SHOW_HEX | SHOW_ASCII },
	{ 0,0 }
};

int
SetEthernetVerbosity(char *letters)
{
	ulong	verbose = 0;
	struct	enet_verbosity *evp = enet_verbose_tbl;

	while(*letters) {
		evp = enet_verbose_tbl;
		while(evp->letter) {
			if (*letters == evp->letter) {
				verbose |= evp->flags;
				break;
			}
			evp++;
		}
		if (evp->letter == 0) {
			printf("Invalid verbosity: '%c'\n",*letters);
			return(CMD_PARAM_ERROR);
		}

		letters++;
	}
	EtherVerbose = verbose;
	return(CMD_SUCCESS);
}

char *EtherHelp[] = {
	"Ethernet interface",
	"-[d:pt:v:V] {on | off | mac | stat | {print I|i|O pkt len}}",
#if INCLUDE_VERBOSEHELP
	"Options...",
	" -d {1|0}     driver debug mode (1=on)",
	" -p {1|0}     promiscuous mode (1=on)",
	" -t           self-test ethernet interface",
	" -v {flgs}    enable specific verbosity...",
	"    0: turn off verbosity",
	"    a: enable ARP trace",
	"    c: print csum errmsg",
	"    C: dump csum errpkt",
	"    d: enable DHCP trace",
#if INCLUDE_GDB
	"    g: enable GDB trace",
#endif
	"    i: incoming packets (minus broadcast)",
	"    I: incoming packets (including broadcast)",
	"    o: outgoing packets",
	"    p: phy r/w accesses",
	"    t: enable TFTP trace",
	"    x: enable hex dump (requires i,I or o)",
	"    X: same as 'x' plus ascii",
	" -V        full verbosity (same as -v Iodtx)",
#endif
	0
};


int
Ether(int argc,char *argv[])
{
	int	opt;

	while ((opt=getopt(argc,argv,"d:p:s:tv:V")) != -1) {
		switch(opt) {
		case 'd':
			if (*optarg == '1')
				EtherVerbose |= SHOW_DRIVER_DEBUG;
			else
				EtherVerbose &= ~SHOW_DRIVER_DEBUG;
			return(CMD_SUCCESS);
		case 'p':
			if (*optarg == '1')
				enablePromiscuousReception();
			else
				disablePromiscuousReception();
			return(CMD_SUCCESS);
		case 't':
			enselftest(1);
			return(CMD_SUCCESS);
		case 'V':
			EtherVerbose = SHOW_ALL;
			return(CMD_SUCCESS);
		case 'v':
			return(SetEthernetVerbosity(optarg));
		default:
			return(CMD_PARAM_ERROR);
		}
	}

	if (argc <= optind)
		return(CMD_SUCCESS);

	if (!strcmp(argv[optind],"off")) {
		enreset();
		EtherIsActive = 0;
		return(CMD_SUCCESS);
	}
	else if (!strcmp(argv[optind],"print")) {
		if (argc == optind+4) {
			int	len, mode;
			ulong overbose;
			struct ether_header *pkt;

			overbose = EtherVerbose;
			switch(argv[optind+1][0]) {
				case 'O':
					mode = ETHER_OUTGOING;
					EtherVerbose = SHOW_ALL;
					break;
				case 'I':
					mode = ETHER_INCOMING;
					EtherVerbose = SHOW_ALL;
					break;
				case 'i':
					mode = ETHER_INCOMING;
					EtherVerbose = (SHOW_ALL & ~SHOW_BROADCAST);
					break;
				default:
					return(CMD_PARAM_ERROR);
			}
			pkt = (struct ether_header *)strtol(argv[optind+2],0,0);
			len = (int)strtol(argv[optind+3],0,0);
			printPkt(pkt,len,mode);
			EtherVerbose = overbose;
			return(CMD_SUCCESS);
		}
		else
			return(CMD_PARAM_ERROR);
	}
	else if (!strcmp(argv[optind],"mac")) {
		storeMac(1);
		return(CMD_SUCCESS);
	}
	else if (!strcmp(argv[optind],"stat")) {
		ShowEthernetStats();
		ShowEtherdevStats();
		ShowDhcpStats();
		ShowTftpStats();
		return(CMD_SUCCESS);
	}
	else if (strcmp(argv[optind],"on"))
		return(CMD_PARAM_ERROR);

	EthernetStartup(EtherVerbose,0);
	return(CMD_SUCCESS);
}

void
ShowEthernetStats(void)
{
	printf("Ethernet interface currently %sabled.\n",
	    EtherIsActive ? "en" : "dis");
	printf("Transmitted frames:      %d\n",EtherXFRAMECnt);
	printf("Received frames:         %d\n",EtherRFRAMECnt);
	printf("IP hdr cksum errors:     %d\n",EtherIPERRCnt);
	printf("UDP pkt cksum errors:    %d\n",EtherUDPERRCnt);
	printf("Max pollethernet nest:   %d\n",MaxEtherPollNesting);
}

/* DisableEthernet():
 * Shut down the interface, and return the state of the
 * interface prior to forcing the shut down.
 */
int
DisableEthernet(void)
{
	int	eia;

	eia = EtherIsActive;
	EtherIsActive = 0;
	IPMonCmdActive = 0;
	DisableEtherdev();
	return(eia);
}

int
EthernetStartup(int verbose, int justreset)
{
	/* Initialize the retransmission delay calculator: */
	RetransmitDelay(DELAY_INIT_DHCP);

	EtherIPERRCnt = 0;
	EtherXFRAMECnt = 0;
	EtherRFRAMECnt = 0;
	EtherUDPERRCnt = 0;
	IPMonCmdActive = 0;
	EtherPollNesting = 0;
	MaxEtherPollNesting = 0;
	DHCPState = DHCPSTATE_NOTUSED;
	if (getenv("ETHERNET_DEBUG"))
		EtherVerbose |= SHOW_DRIVER_DEBUG;
	else
		EtherVerbose = 0;

	/* Setup all the IP addresses used by the monitor... */
	if (getAddresses() == -1)
		return(-1);

	/* Call device specific startup code: */
	if (EtherdevStartup(verbose) < 0)
		return(-1);

	/* Initialize some TFTP state... */
	tftpInit();

#if INCLUDE_DHCPBOOT
	/* If EthernetStartup is called as a result of anything other than a
	 * target reset, don't startup any DHCP/BOOTP transaction...
	 */
	if (!justreset)
		dhcpDisable();
#endif
	EtherIsActive = 1;
	return(0);
}

/* pollethernet():
 *	Called at a few critical points in the monitor code to poll the
 *	ethernet device and keep track of the state of DHCP and TFTP.
 */
int
pollethernet(void)
{
	int	pcnt;

	if ((!EtherIsActive) || (EtherPollNesting > 4))
		return(0);

	EtherPollNesting++;
	if (EtherPollNesting > MaxEtherPollNesting)
		MaxEtherPollNesting = EtherPollNesting;

	pcnt = polletherdev();
	if (IPMonCmdLine[0] != 0)
		executeMONCMD();

	dhcpStateCheck();
	tftpStateCheck();

	EtherPollNesting--;
	return(pcnt);
}

/* getAddresses():
 * Try getting ether/ip addresses from environment.
 * If not there, try getting them from some target-specific interface.
 * If not there, then get them from raw flash.
 * If not there, just use the hard-coded default.
 * Also, load all port numbers from shell variables, else default.
 *
 * Discussion regarding etheraddr[]...
 * The purpose of this array is to provide a point in flash that is 
 * initialized to 0xff by the code (see reset.s).  This then allows some
 * other mechanism (storeMAC() or bed of nails, etc..) to program this
 * location to some non-0xff value.  This allows the base monitor image to
 * be common, but then be modified by other code or external hardware. 
 */

int
getAddresses(void)
{
	char	*mcmdPort, *gdbPort, *dcliPort, *dsrvPort, *tftpPort;

	/* Set up port numbers: */
	mcmdPort = getenv("MCMDPORT");
	gdbPort  = getenv("GDBPORT");
	dcliPort = getenv("DCLIPORT");
	dsrvPort = getenv("DSRVPORT");
	tftpPort = getenv("TFTPPORT");

	if (mcmdPort)
		MoncmdPort = (ushort)strtol(mcmdPort,0,0);
	else
		MoncmdPort = IPPORT_MONCMD;
	if (gdbPort)
		GdbPort = (ushort)strtol(gdbPort,0,0);
	else
		GdbPort = IPPORT_GDB;
	if (dcliPort)
		DhcpClientPort = (ushort)strtol(dcliPort,0,0);
	else
		DhcpClientPort = IPPORT_DHCP_CLIENT;
	if (dsrvPort)
		DhcpServerPort = (ushort)strtol(dsrvPort,0,0);
	else
		DhcpServerPort = IPPORT_DHCP_SERVER;
	if (tftpPort)
		TftpPort = (ushort)strtol(tftpPort,0,0);
	else
		TftpPort = IPPORT_TFTP;				/* 69	*/
	TftpSrcPort = IPPORT_TFTPSRC;			/* 8888 */

	/* Retrieve MAC address and store in shell variable ETHERADD...
	 * First see if the shell variable is already loaded.
	 * If not see if some target-specific interface has it.
	 * If not see if the the string is stored in raw flash (usually this
	 *   storage is initialized in reset.s of the target-specific code).
	 * Finally, as a last resort, use the default set up in config.h.
 	 */
 	 //stone  add for set MAC use DEFAULT_ETHERADD;
	if (!(Etheradd = getenv("ETHERADD"))) {
		if (!(Etheradd = extGetEtherAdd())) {
			//if (etheraddr[0] != 0xff)
				//Etheradd = etheraddr;
			//else
				Etheradd = DEFAULT_ETHERADD;
		}
		//char *stone = extGetEtherAdd();
		setenv("ETHERADD",Etheradd);
	}

//stone add for test
	//Etheradd = DEFAULT_ETHERADD;
	//setenv("ETHERADD",Etheradd);
//stone add end
	/* Apply the same logic as above to the IP address... */


	if (!(IPadd = getenv("IPADD"))) {
		if (!(IPadd = extGetIpAdd()))
			IPadd = DEFAULT_IPADD;
		setenv("IPADD",IPadd);
	}
	
	/* Convert addresses to binary:
	 */
	if (EtherToBin(Etheradd,BinEnetAddr) < 0)
		return(-1);
	/* If the ethernet address is 0:0:0:0:0:0, then we
	 * return an error here so that the interface is not
	 * brought up.
	 */
	if (memcmp(BinEnetAddr,AllZeroAddr,6) == 0) {
		static int firsttime;

		if (firsttime == 0) {
			printf("\nNULL MAC address, network interface disabled.\n");
			firsttime = 1;
		}
		return(-1);
	}

#if INCLUDE_DHCPBOOT
	if (DhcpIPCheck(IPadd) == -1)
		return(-1);
#else
	if (IpToBin(IPadd,BinIpAddr) < 0)
		return(-1);
#endif
	/* Initialize a unique number based on MAC: */
	UniqueIpId = xcrc16(BinEnetAddr,6);

	return(0);
}

/* processPACKET():
 *	This is the top level of the message processing after a complete
 *	packet has been received over ethernet.  It's all just a lot of
 *	parsing to determine whether the message is for this board's IP
 *	address (broadcast reception may be enabled), and the type of
 *	incoming protocol.  Once that is determined, the packet is either
 *	processed (TFTP, DHCP, ARP, ICMP-ECHO, etc...) or discarded.
 */
void
processPACKET(struct ether_header *ehdr, ushort size)
{
	int	i;
	ushort	*datap, udpport;
	ulong	csum;
	struct ip *ihdr;
	struct Udphdr *uhdr;

	WATCHDOG_MACRO;

	EtherRFRAMECnt++;
	printPkt(ehdr,size,ETHER_INCOMING);

	/* AppPktPtr is used by monRecvEnetPkt() so that an application can
	 * use the monitor's ethernet driver.  For more info, refer to notes

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -