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

📄 arp.c

📁 umon bootloader source code, support mips cpu.
💻 C
字号:
/* arpstuff.c:
 *	This code supports some basic arp/rarp 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"
#if INCLUDE_ETHERNET
#include "endian.h"
#include "genlib.h"
#include "ether.h"
#include "stddefs.h"
#include "cli.h"
#include "timer.h"

static void	ArpFlush(void);
static void ArpShow(char *);
static int	ArpStore(uchar *,uchar *);
static int	IpIsOnThisNet(uchar *);

/* arpcache[]:
 *	Used to store the most recent set of IP-to-MAC address correlations.
 */
struct arpcache {
	uchar	ip[4];
	uchar	ether[6];
} ArpCache[SIZEOFARPCACHE];

/* ArpIdx & ArpTot:
 *	Used for keeping track of current arp cache content.
 */
int ArpIdx, ArpTot;

/* ArpStore():
 *	Called with binary ip and ethernet addresses.
 *	It will store that set away in the cache.
 */
int
ArpStore(uchar *ip,uchar *ether)
{
	if (EtherFromCache(ip))
		return(0);
	if (ArpIdx >= SIZEOFARPCACHE)
		ArpIdx=0;
	memcpy((char *)ArpCache[ArpIdx].ip,(char *)ip,4);
	memcpy((char *)ArpCache[ArpIdx].ether,(char *)ether,6);
	ArpIdx++;
	ArpTot++;
	return(0);
}

/* EtherFromCache():
 *	Called with a binary (4-byte) ip address.  If a match is found
 *	in the cache, return a pointer to that ethernet address; else
 *	return NULL.
 */
uchar *
EtherFromCache(uchar *ip)
{
	int	i, max;

	if (ArpTot >= SIZEOFARPCACHE)
		max = SIZEOFARPCACHE;
		else
		max = ArpTot;

	for(i=0;i<SIZEOFARPCACHE;i++) {
		if (!memcmp(ArpCache[i].ip,ip,4))
			return(ArpCache[i].ether);
	}
	return(0);
}

void
ArpFlush(void)
{
	int	i;

	for(i=0;i<SIZEOFARPCACHE;i++) {
		memset(ArpCache[i].ip,0,4);
		memset(ArpCache[i].ether,0,6);
	}
	ArpIdx = ArpTot = 0;
}

/* ArpShow():
 *	Dump the content of the current arp cache.
 */
void
ArpShow(char *ip)
{
	struct	arpcache *ap, *end;

	if (ArpTot < SIZEOFARPCACHE)
		end = &ArpCache[ArpTot];
		else
		end = &ArpCache[SIZEOFARPCACHE];

	for (ap=ArpCache;ap<end;ap++) {
		if ((!ip) || (!memcmp(ip,ap->ip,4))) {
			printf("%02x:%02x:%02x:%02x:%02x:%02x = ",
			    ap->ether[0], ap->ether[1], ap->ether[2], ap->ether[3],
			    ap->ether[4], ap->ether[5]);
			printf("%d.%d.%d.%d\n",
			    ap->ip[0], ap->ip[1], ap->ip[2], ap->ip[3]);
		}
	}
}

/* SendArpResp():
 *	Called in response to an ARP REQUEST.  The incoming ethernet
 *	header pointer points to the memory area that contains the incoming
 *	ethernet packet that this function is called in response to.
 *	In other words, it is used to fill the majority of the response
 *	packet fields.
 */
int
SendArpResp(struct ether_header *re)
{
	struct ether_header *te;
	struct arphdr *ta, *ra;

	te = (struct ether_header *) getXmitBuffer();
	memcpy((char *)&(te->ether_shost),BinEnetAddr,6);
	memcpy((char *)&(te->ether_dhost),(char *)&(re->ether_shost),6);
	te->ether_type = ecs(ETHERTYPE_ARP);

	ta = (struct arphdr *) (te + 1);
	ra = (struct arphdr *) (re + 1);
	ta->hardware = ra->hardware;
	ta->protocol = ra->protocol;
	ta->hlen = ra->hlen;
	ta->plen = ra->plen;
	ta->operation = ARP_RESPONSE;
	memcpy(ta->senderha,BinEnetAddr,6);
	memcpy(ta->senderia,ra->targetia,4);
	memcpy(ta->targetha,ra->senderha,6);
	memcpy(ta->targetia,ra->senderia,4);
	self_ecs(ta->hardware);
	self_ecs(ta->protocol);
	self_ecs(ta->operation);
	sendBuffer(ARPSIZE);
	return(0);
}

/* SendArpRequest():
 */
int
SendArpRequest(uchar *ip)
{
	struct ether_header *te;
	struct arphdr *ta;

	/* Populate the ethernet header: */
	te = (struct ether_header *) getXmitBuffer();
	memcpy((char *)&(te->ether_shost),BinEnetAddr,6);
	memcpy((char *)&(te->ether_dhost),BroadcastAddr,6);
	te->ether_type = ecs(ETHERTYPE_ARP);

	/* Populate the arp header: */
	ta = (struct arphdr *) (te + 1);
	ta->hardware = ecs(1);		/* 1 for ethernet */
	ta->protocol = ecs(ETHERTYPE_IP);
	ta->hlen = 6;		/* Length of hdware (ethernet) address */
	ta->plen = 4;		/* Length of protocol (ip) address */
	ta->operation = ecs(ARP_REQUEST);
	memcpy(ta->senderha,BinEnetAddr,6);
	memcpy(ta->senderia,BinIpAddr,4);
	memcpy(ta->targetha,BroadcastAddr,6);
	memcpy(ta->targetia,ip,4);
	sendBuffer(ARPSIZE);
	return(0);
}

/* GetBinNetMask():
 *  Return a subnet mask in binary form.
 *	Since this function needs a netmask, if NETMASK is not set, then
 *	it uses the default based on the upper 3 bits of the IP address
 *	(refer to TCP/IP Illustrated Volume 1 Pg8 for details).
 */
void
GetBinNetMask(uchar *binnetmask)
{
	char	*nm, class;

	nm = getenv("NETMASK");
	if (!nm) {
		memset(binnetmask,0xff,4);
		if ((BinIpAddr[0] & 0xe0) == 0xc0) {		/* Class C */
			binnetmask[3] = 0;
			class = 'C';
		}
		else if ((BinIpAddr[0] & 0xc0) == 0x80) {	/* Class B */
			binnetmask[3] = 0;
			binnetmask[2] = 0;
			class = 'B';
		}
		else if ((BinIpAddr[0] & 0x80) == 0x00) {	/* Class A */
			binnetmask[3] = 0;
			binnetmask[2] = 0;
			binnetmask[1] = 0;
			class = 'A';
		}
		else
			class = '?';
	}
	else
		IpToBin(nm,binnetmask);
}

/* IpIsOnThisNet():
 *	Return 1 if the incoming ip is on this subnet; else 0.
 *	For each bit in the netmask that is set to 1...
 *	If the corresponding bits in the incoming IP and this board's IP
 *	do not match, return 0; else return 1.
 */
int
IpIsOnThisNet(uchar *ip)
{
	int		i;
	uchar	binnetmask[8];

	GetBinNetMask(binnetmask);

	for(i=0;i<4;i++) {
		if ((ip[i] & binnetmask[i]) != (BinIpAddr[i] & binnetmask[i])) {
			return(0);
		}
	}
	return(1);
}

/* Arp():
 *	If no args, just dump the arp cache.
 *	If arg is present, then assume it to be an ip address.  
 *	Check the arp cache for the presence of that ip<->correlation, if
 *	present, print it; else issue and arp request for that IP and wait
 *	for a response.
 */

char *ArpHelp[] = {
	"Address resolution protocol",
	"-[fps:v] [IP]",
#if INCLUDE_VERBOSEHELP
	" -f   flush cache",
	" -p   proxy arp",
	" -s{eadr}   store eadr/IP into cache",
	" -v   verbose",
#endif
	0,
};

int
Arp(int argc,char *argv[])
{
	int		opt, proxyarp;
	char	binip[8], binether[8], *storeether;

	proxyarp = 0;
	storeether = (char *)0;
	while ((opt=getopt(argc,argv,"fps:v")) != -1) {
		switch(opt) {
		case 'f':	/* Flush current arp cache */
			ArpFlush();
			break;
		case 's':	/* Store specified IP/MAC combination in arp cache. */
			storeether = optarg;
			break;
		case 'p':	/* Assume gateway will run proxy arp */
			proxyarp = 1;
			break;
		case 'v':	/* Enable verbosity for ARP. */
			EtherVerbose |= SHOW_ARP;
			break;
		default:
			return(CMD_PARAM_ERROR);
		}
	}

	if (argc == (optind+1)) {
		IpToBin(argv[optind],binip);
		if (storeether) {
			EtherToBin(storeether,binether);
			ArpStore(binip,binether);
		}
		else {
			if (ArpEther(binip,0,proxyarp))
				ArpShow(binip);
		}
	}
	else
		ArpShow(0);
	EtherVerbose &= ~ SHOW_ARP;
	return(CMD_SUCCESS);
}

/* ArpEther():
 *	Retrieve the ethernet address that corresponds to the incoming IP 
 *	address.  First check the local ArpCache[], then if not found issue
 *	an ARP request... If the incoming IP is on this net, then issue the
 *	request for the MAC address of that IP; otherwise, issue the request
 *	for this net's GATEWAY.
 */
uchar *
ArpEther(uchar *binip, uchar *ecpy, int proxyarp)
{
	char	*gip;
	struct	elapsed_tmr tmr;
	uchar	gbinip[8], *Ip, *ep;
	int		timeoutsecs, retry;

	if (!EtherIsActive) {
		printf("Ethernet disabled\n");
		return(0);
	}

	/* First check local cache. If found, return with pointer to MAC. */
	ep = EtherFromCache(binip);
	if (ep) {
		if (ecpy) {
			memcpy(ecpy,ep,6);
			ep = ecpy;
		}
		return(ep);
	}

	retry = 0;
	RetransmitDelay(DELAY_INIT_ARP);
	while(1) {
		/* If IP is not on this net, the get the GATEWAY IP address. */
		if (!proxyarp && !IpIsOnThisNet(binip)) {
			gip = getenv("GIPADD");
			if (gip) {
				IpToBin(gip,gbinip);
				if (!IpIsOnThisNet(gbinip)) {
					printf("GIPADD/IPADD subnet confusion.\n");
					return(0);
				}
				ep = EtherFromCache(gbinip);
				if (ep) {
					if (ecpy) {
						memcpy(ecpy,ep,6);
						ep = ecpy;
					}
					return(ep);
				}
				SendArpRequest(gbinip);
				Ip = gbinip;
			}
			else {
				SendArpRequest(binip);
				Ip = binip;
			}
		}
		else {
			SendArpRequest(binip);
			Ip = binip;
		}
		if (retry) {
			printf("  ARP Retry #%d (%d.%d.%d.%d)\n",retry,
				binip[0],binip[1],binip[2],binip[3]);
		}

		/* Now that the request has been issued, wait for a while to see if
		 * the ARP cache is loaded with the result of the request.
		 */
		timeoutsecs = RetransmitDelay(DELAY_OR_TIMEOUT_RETURN);
		if (timeoutsecs == RETRANSMISSION_TIMEOUT)
			break;
		startElapsedTimer(&tmr,timeoutsecs*1000);
		while(!msecElapsed(&tmr)) {
			ep = EtherFromCache(Ip);
			if (ep)
				break;
			pollethernet();
		}
		if (ep) {
			if (ecpy) {
				memcpy(ecpy,ep,6);
				ep = ecpy;
			}
			return(ep);
		}
		RetransmitDelay(DELAY_INCREMENT);
		retry++;
	}
	if ((EtherVerbose & SHOW_ARP) && (retry))
		printf("  ARP giving up\n");
	return(0);
}

/* processRARP();
 *	Called by the fundamental ethernet driver code to process a RARP
 *	request.
 */
int
processRARP(struct ether_header *ehdr,ushort size)
{
	struct	arphdr *arpp;

	arpp = (struct arphdr *)(ehdr+1);
	self_ecs(arpp->hardware);
	self_ecs(arpp->protocol);
	self_ecs(arpp->operation);

	switch(arpp->operation) {
	case RARP_RESPONSE:
		if (!memcmp(arpp->targetha,BinEnetAddr,6)) {
			if (EtherVerbose & SHOW_ARP) {
				printf("  RARP Response from %d.%d.%d.%d\n",
				    arpp->senderia[0],arpp->senderia[1],
				    arpp->senderia[2],arpp->senderia[3]);
				printf("  MY IP: from %d.%d.%d.%d\n",
				    arpp->targetia[0],arpp->targetia[1],
				    arpp->targetia[2],arpp->targetia[3]);
			}
			memcpy(BinIpAddr,arpp->targetia,6);
		}
		break;
	case RARP_REQUEST:
		break;
	default:
		printf("  Invalid RARP operation: 0x%x\n",arpp->operation);
		return(-1);
	}
	return(0);
}

/* processARP();
 *	Called by the fundamental ethernet driver code to process a ARP
 *	request.
 */
char *
processARP(struct ether_header *ehdr,ushort size)
{
	struct	arphdr *arpp;

	arpp = (struct arphdr *)(ehdr+1);
	self_ecs(arpp->hardware);
	self_ecs(arpp->protocol);
	self_ecs(arpp->operation);

	switch(arpp->operation) {
	case ARP_REQUEST:
		if (!memcmp(arpp->targetia,BinIpAddr,4)) {
			ArpStore(arpp->senderia,arpp->senderha);
			SendArpResp(ehdr);
		}
		break;
	case ARP_RESPONSE:
		if (!memcmp(arpp->targetia,BinIpAddr,4)) {
			ArpStore(arpp->senderia,arpp->senderha);
		}
		break;
	default:
		//printf("  Invalid ARP operation: 0x%x\n",arpp->operation);
		printPkt(ehdr,(int)size,ETHER_INCOMING);
		return((char *)0);
	}
	return((char *)(arpp + 1));
}

#endif

⌨️ 快捷键说明

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