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

📄 arp.c

📁 Minix比较全的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*arp.cCopyright 1995 Philip Homburg*/#include "inet.h"#include "type.h"#include "arp.h"#include "assert.h"#include "buf.h"#include "clock.h"#include "event.h"#include "eth.h"#include "io.h"#include "sr.h"THIS_FILE#define ARP_CACHE_NR	 256#define AP_REQ_NR	  32#define ARP_HASH_NR	256#define ARP_HASH_MASK	0xff#define ARP_HASH_WIDTH	4#define MAX_ARP_RETRIES		5#define ARP_TIMEOUT		(HZ/2+1)	/* .5 seconds */#ifndef ARP_EXP_TIME#define ARP_EXP_TIME		(20L*60L*HZ)	/* 20 minutes */#endif#define ARP_NOTRCH_EXP_TIME	(30*HZ)		/* 30 seconds */#define ARP_INUSE_OFFSET	(60*HZ)	/* an entry in the cache can be deleted					   if its not used for 1 minute */typedef struct arp46{	ether_addr_t a46_dstaddr;	ether_addr_t a46_srcaddr;	ether_type_t a46_ethtype;	union	{		struct		{			u16_t a_hdr, a_pro;			u8_t a_hln, a_pln;			u16_t a_op;			ether_addr_t a_sha;			u8_t a_spa[4];			ether_addr_t a_tha;			u8_t a_tpa[4];		} a46_data;		char    a46_dummy[ETH_MIN_PACK_SIZE-ETH_HDR_SIZE];	} a46_data;} arp46_t;#define a46_hdr a46_data.a46_data.a_hdr#define a46_pro a46_data.a46_data.a_pro#define a46_hln a46_data.a46_data.a_hln#define a46_pln a46_data.a46_data.a_pln#define a46_op a46_data.a46_data.a_op#define a46_sha a46_data.a46_data.a_sha#define a46_spa a46_data.a46_data.a_spa#define a46_tha a46_data.a46_data.a_tha#define a46_tpa a46_data.a46_data.a_tpatypedef struct arp_port{	int ap_flags;	int ap_state;	int ap_eth_port;	int ap_ip_port;	int ap_eth_fd;	ether_addr_t ap_ethaddr;	/* Ethernet address of this port */	ipaddr_t ap_ipaddr;		/* IP address of this port */	struct arp_req	{		timer_t ar_timer;		int ar_entry;		int ar_req_count;	} ap_req[AP_REQ_NR];	arp_func_t ap_arp_func;	acc_t *ap_sendpkt;	acc_t *ap_sendlist;	acc_t *ap_reclist;	event_t ap_event;} arp_port_t;#define APF_EMPTY	0x00#define APF_ARP_RD_IP	0x01#define APF_ARP_RD_SP	0x02#define APF_ARP_WR_IP	0x04#define APF_ARP_WR_SP	0x08#define APF_INADDR_SET	0x10#define APF_SUSPEND	0x20#define APS_INITIAL	1#define	APS_GETADDR	2#define	APS_ARPSTART	3#define	APS_ARPPROTO	4#define	APS_ARPMAIN	5#define	APS_ERROR	6typedef struct arp_cache{	int ac_flags;	int ac_state;	ether_addr_t ac_ethaddr;	ipaddr_t ac_ipaddr;	arp_port_t *ac_port;	time_t ac_expire;	time_t ac_lastuse;} arp_cache_t;#define ACF_EMPTY	0#define ACF_PERM	1#define ACF_PUB		2#define ACS_UNUSED	0#define ACS_INCOMPLETE	1#define ACS_VALID	2#define ACS_UNREACHABLE	3PRIVATE struct arp_hash_ent{	arp_cache_t *ahe_row[ARP_HASH_WIDTH];} arp_hash[ARP_HASH_NR];PRIVATE arp_port_t *arp_port_table;PRIVATE	arp_cache_t *arp_cache;PRIVATE int arp_cache_nr;FORWARD acc_t *arp_getdata ARGS(( int fd, size_t offset,	size_t count, int for_ioctl ));FORWARD int arp_putdata ARGS(( int fd, size_t offset,	acc_t *data, int for_ioctl ));FORWARD void arp_main ARGS(( arp_port_t *arp_port ));FORWARD void arp_timeout ARGS(( int ref, timer_t *timer ));FORWARD void setup_write ARGS(( arp_port_t *arp_port ));FORWARD void setup_read ARGS(( arp_port_t *arp_port ));FORWARD void do_reclist ARGS(( event_t *ev, ev_arg_t ev_arg ));FORWARD void process_arp_pkt ARGS(( arp_port_t *arp_port, acc_t *data ));FORWARD void client_reply ARGS(( arp_port_t *arp_port,	ipaddr_t ipaddr, ether_addr_t *ethaddr ));FORWARD arp_cache_t *find_cache_ent ARGS(( arp_port_t *arp_port,	ipaddr_t ipaddr ));FORWARD arp_cache_t *alloc_cache_ent ARGS(( int flags ));FORWARD void arp_buffree ARGS(( int priority ));#ifdef BUF_CONSISTENCY_CHECKFORWARD void arp_bufcheck ARGS(( void ));#endifPUBLIC void arp_prep(){	arp_port_table= alloc(eth_conf_nr * sizeof(arp_port_table[0]));	arp_cache_nr= ARP_CACHE_NR;	if (arp_cache_nr < (eth_conf_nr+1)*AP_REQ_NR)	{		arp_cache_nr= (eth_conf_nr+1)*AP_REQ_NR;		printf("arp: using %d cache entries instead of %d\n",			arp_cache_nr, ARP_CACHE_NR);	}	arp_cache= alloc(arp_cache_nr * sizeof(arp_cache[0]));}PUBLIC void arp_init(){	arp_port_t *arp_port;	arp_cache_t *cache;	int i;	assert (BUF_S >= sizeof(struct nwio_ethstat));	assert (BUF_S >= sizeof(struct nwio_ethopt));	assert (BUF_S >= sizeof(arp46_t));	for (i=0, arp_port= arp_port_table; i<eth_conf_nr; i++, arp_port++)	{		arp_port->ap_state= APS_ERROR;	/* Mark all ports as						 * unavailable */	}	cache= arp_cache;	for (i=0; i<arp_cache_nr; i++, cache++)	{		cache->ac_state= ACS_UNUSED;		cache->ac_flags= ACF_EMPTY;		cache->ac_expire= 0;		cache->ac_lastuse= 0;	}#ifndef BUF_CONSISTENCY_CHECK	bf_logon(arp_buffree);#else	bf_logon(arp_buffree, arp_bufcheck);#endif}PRIVATE void arp_main(arp_port)arp_port_t *arp_port;{	int result;	switch (arp_port->ap_state)	{	case APS_INITIAL:		arp_port->ap_eth_fd= eth_open(arp_port->ap_eth_port,			arp_port->ap_eth_port, arp_getdata, arp_putdata,			0 /* no put_pkt */, 0 /* no select_res */);		if (arp_port->ap_eth_fd<0)		{			DBLOCK(1, printf("arp[%d]: unable to open eth[%d]\n",				arp_port-arp_port_table,				arp_port->ap_eth_port));			return;		}		arp_port->ap_state= APS_GETADDR;		result= eth_ioctl (arp_port->ap_eth_fd, NWIOGETHSTAT);		if ( result == NW_SUSPEND)		{			arp_port->ap_flags |= APF_SUSPEND;			return;		}		assert(result == NW_OK);		/* fall through */	case APS_GETADDR:		/* Wait for IP address */		if (!(arp_port->ap_flags & APF_INADDR_SET))			return;		/* fall through */	case APS_ARPSTART:		arp_port->ap_state= APS_ARPPROTO;		result= eth_ioctl (arp_port->ap_eth_fd, NWIOSETHOPT);		if (result==NW_SUSPEND)		{			arp_port->ap_flags |= APF_SUSPEND;			return;		}		assert(result == NW_OK);		/* fall through */	case APS_ARPPROTO:		arp_port->ap_state= APS_ARPMAIN;		setup_write(arp_port);		setup_read(arp_port);		return;	default:		ip_panic((		 "arp_main(&arp_port_table[%d]) called but ap_state=0x%x\n",			arp_port->ap_eth_port, arp_port->ap_state ));	}}PRIVATE acc_t *arp_getdata (fd, offset, count, for_ioctl)int fd;size_t offset;size_t count;int for_ioctl;{	arp_port_t *arp_port;	acc_t *data;	int result;	arp_port= &arp_port_table[fd];	switch (arp_port->ap_state)	{	case APS_ARPPROTO:		if (!count)		{			result= (int)offset;			if (result<0)			{				arp_port->ap_state= APS_ERROR;				break;			}			if (arp_port->ap_flags & APF_SUSPEND)			{				arp_port->ap_flags &= ~APF_SUSPEND;				arp_main(arp_port);			}			return NW_OK;		}		assert ((!offset) && (count == sizeof(struct nwio_ethopt)));		{			struct nwio_ethopt *ethopt;			acc_t *acc;			acc= bf_memreq(sizeof(*ethopt));			ethopt= (struct nwio_ethopt *)ptr2acc_data(acc);			ethopt->nweo_flags= NWEO_COPY|NWEO_EN_BROAD|				NWEO_TYPESPEC;			ethopt->nweo_type= HTONS(ETH_ARP_PROTO);			return acc;		}	case APS_ARPMAIN:		assert (arp_port->ap_flags & APF_ARP_WR_IP);		if (!count)		{			data= arp_port->ap_sendpkt;			arp_port->ap_sendpkt= NULL;			assert(data);			bf_afree(data); data= NULL;			result= (int)offset;			if (result<0)			{				DIFBLOCK(1, (result != NW_SUSPEND),					printf(				"arp[%d]: write error on port %d: error %d\n",					fd, arp_port->ap_eth_fd, result));				arp_port->ap_state= APS_ERROR;				break;			}			arp_port->ap_flags &= ~APF_ARP_WR_IP;			if (arp_port->ap_flags & APF_ARP_WR_SP)				setup_write(arp_port);			return NW_OK;		}		assert (offset+count <= sizeof(arp46_t));		data= arp_port->ap_sendpkt;		assert(data);		data= bf_cut(data, offset, count);		return data;	default:		printf("arp_getdata(%d, 0x%d, 0x%d) called but ap_state=0x%x\n",			fd, offset, count, arp_port->ap_state);		break;	}	return 0;}PRIVATE int arp_putdata (fd, offset, data, for_ioctl)int fd;size_t offset;acc_t *data;int for_ioctl;{	arp_port_t *arp_port;	int result;	struct nwio_ethstat *ethstat;	ev_arg_t ev_arg;	acc_t *tmpacc;	arp_port= &arp_port_table[fd];	if (arp_port->ap_flags & APF_ARP_RD_IP)	{		if (!data)		{			result= (int)offset;			if (result<0)			{				DIFBLOCK(1, (result != NW_SUSPEND), printf(				"arp[%d]: read error on port %d: error %d\n",					fd, arp_port->ap_eth_fd, result));				return NW_OK;			}			if (arp_port->ap_flags & APF_ARP_RD_SP)			{				arp_port->ap_flags &= ~(APF_ARP_RD_IP|					APF_ARP_RD_SP);				setup_read(arp_port);			}			else				arp_port->ap_flags &= ~(APF_ARP_RD_IP|					APF_ARP_RD_SP);			return NW_OK;		}		assert (!offset);		/* Warning: the above assertion is illegal; puts and gets of		   data can be brokenup in any piece the server likes. However		   we assume that the server is eth.c and it transfers only		   whole packets.		   */		data= bf_packIffLess(data, sizeof(arp46_t));		if (data->acc_length >= sizeof(arp46_t))		{			if (!arp_port->ap_reclist)			{				ev_arg.ev_ptr= arp_port;				ev_enqueue(&arp_port->ap_event, do_reclist,					ev_arg);			}			if (data->acc_linkC != 1)			{				tmpacc= bf_dupacc(data);				bf_afree(data);				data= tmpacc;				tmpacc= NULL;			}			data->acc_ext_link= arp_port->ap_reclist;			arp_port->ap_reclist= data;		}		else			bf_afree(data);		return NW_OK;	}	switch (arp_port->ap_state)	{	case APS_GETADDR:		if (!data)		{			result= (int)offset;			if (result<0)			{				arp_port->ap_state= APS_ERROR;				break;			}			if (arp_port->ap_flags & APF_SUSPEND)			{				arp_port->ap_flags &= ~APF_SUSPEND;				arp_main(arp_port);			}			return NW_OK;		}		compare (bf_bufsize(data), ==, sizeof(*ethstat));		data= bf_packIffLess(data, sizeof(*ethstat));		compare (data->acc_length, ==, sizeof(*ethstat));		ethstat= (struct nwio_ethstat *)ptr2acc_data(data);		arp_port->ap_ethaddr= ethstat->nwes_addr;		bf_afree(data);		return NW_OK;	default:		printf("arp_putdata(%d, 0x%d, 0x%lx) called but ap_state=0x%x\n",			fd, offset, (unsigned long)data, arp_port->ap_state);		break;	}	return EGENERIC;}PRIVATE void setup_read(arp_port)arp_port_t *arp_port;{	int result;	while (!(arp_port->ap_flags & APF_ARP_RD_IP))	{		arp_port->ap_flags |= APF_ARP_RD_IP;		result= eth_read (arp_port->ap_eth_fd, ETH_MAX_PACK_SIZE);		if (result == NW_SUSPEND)		{			arp_port->ap_flags |= APF_ARP_RD_SP;			return;		}		DIFBLOCK(1, (result != NW_OK),			printf("arp[%d]: eth_read(..,%d)=%d\n",			arp_port-arp_port_table, ETH_MAX_PACK_SIZE, result));	}}PRIVATE void setup_write(arp_port)arp_port_t *arp_port;{	int result;	acc_t *data;	for(;;)	{		data= arp_port->ap_sendlist;		if (!data)			break;		arp_port->ap_sendlist= data->acc_ext_link;		if (arp_port->ap_ipaddr == HTONL(0x00000000))		{			/* Interface is down */			printf(		"arp[%d]: not sending ARP packet, interface is down\n",				arp_port-arp_port_table);			bf_afree(data); data= NULL;			continue;		}		assert(!arp_port->ap_sendpkt);		arp_port->ap_sendpkt= data; data= NULL;					arp_port->ap_flags= (arp_port->ap_flags & ~APF_ARP_WR_SP) |			APF_ARP_WR_IP;		result= eth_write(arp_port->ap_eth_fd, sizeof(arp46_t));		if (result == NW_SUSPEND)		{			arp_port->ap_flags |= APF_ARP_WR_SP;			break;		}		if (result<0)		{			DIFBLOCK(1, (result != NW_SUSPEND),				printf("arp[%d]: eth_write(..,%d)=%d\n",				arp_port-arp_port_table, sizeof(arp46_t),				result));			return;		}	}}PRIVATE void do_reclist(ev, ev_arg)event_t *ev;ev_arg_t ev_arg;{	arp_port_t *arp_port;	acc_t *data;	arp_port= ev_arg.ev_ptr;	assert(ev == &arp_port->ap_event);	while (data= arp_port->ap_reclist, data != NULL)	{		arp_port->ap_reclist= data->acc_ext_link;		process_arp_pkt(arp_port, data);		bf_afree(data);	}}PRIVATE void process_arp_pkt (arp_port, data)arp_port_t *arp_port;acc_t *data;{	int i, entry, do_reply;	arp46_t *arp;	u16_t *p;	arp_cache_t *ce, *cache;	struct arp_req *reqp;	time_t curr_time;	ipaddr_t spa, tpa;	curr_time= get_time();	arp= (arp46_t *)ptr2acc_data(data);	memcpy(&spa, arp->a46_spa, sizeof(ipaddr_t));	memcpy(&tpa, arp->a46_tpa, sizeof(ipaddr_t));	if (arp->a46_hdr != HTONS(ARP_ETHERNET) ||		arp->a46_hln != 6 ||		arp->a46_pro != HTONS(ETH_IP_PROTO) ||		arp->a46_pln != 4)		return;	if (arp_port->ap_ipaddr == HTONL(0x00000000))	{		/* Interface is down */#if DEBUG		printf("arp[%d]: dropping ARP packet, interface is down\n",			arp_port-arp_port_table);#endif		return;	}	ce= find_cache_ent(arp_port, spa);	cache= NULL;	/* lint */	do_reply= 0;	if (arp->a46_op != HTONS(ARP_REQUEST))		;	/* No need to reply */	else if (tpa == arp_port->ap_ipaddr)		do_reply= 1;	else	{		/* Look for a published entry */		cache= find_cache_ent(arp_port, tpa);		if (cache)		{			if (cache->ac_flags & ACF_PUB)			{				/* Published entry */				do_reply= 1;			}			else			{				/* Nothing to do */				cache= NULL;			}		}	}	if (ce == NULL)	{		if (!do_reply)			return;		DBLOCK(0x10, printf("arp[%d]: allocating entry for ",			arp_port-arp_port_table);			writeIpAddr(spa); printf("\n"));		ce= alloc_cache_ent(ACF_EMPTY);		ce->ac_flags= ACF_EMPTY;		ce->ac_state= ACS_VALID;		ce->ac_ethaddr= arp->a46_sha;		ce->ac_ipaddr= spa;		ce->ac_port= arp_port;		ce->ac_expire= curr_time+ARP_EXP_TIME;		ce->ac_lastuse= curr_time-ARP_INUSE_OFFSET; /* never used */	}	if (ce->ac_state == ACS_INCOMPLETE || ce->ac_state == ACS_UNREACHABLE)	{		ce->ac_ethaddr= arp->a46_sha;		if (ce->ac_state == ACS_INCOMPLETE)		{			/* Find request entry */			entry= ce-arp_cache;			for (i= 0, reqp= arp_port->ap_req; i<AP_REQ_NR; 				i++, reqp++)			{				if (reqp->ar_entry == entry)					break;			}			assert(i < AP_REQ_NR);			clck_untimer(&reqp->ar_timer);			reqp->ar_entry= -1;						ce->ac_state= ACS_VALID;			client_reply(arp_port, spa, &arp->a46_sha);		}		else			ce->ac_state= ACS_VALID;	}	/* Update fields in the arp cache. */	if (memcmp(&ce->ac_ethaddr, &arp->a46_sha,		sizeof(ce->ac_ethaddr)) != 0)	{		printf("arp[%d]: ethernet address for IP address ",			arp_port-arp_port_table);		writeIpAddr(spa);		printf(" changed from ");		writeEtherAddr(&ce->ac_ethaddr);		printf(" to ");		writeEtherAddr(&arp->a46_sha);		printf("\n");		ce->ac_ethaddr= arp->a46_sha;	}	ce->ac_expire= curr_time+ARP_EXP_TIME;	if (do_reply)	{		data= bf_memreq(sizeof(arp46_t));		arp= (arp46_t *)ptr2acc_data(data);		/* Clear padding */		assert(sizeof(arp->a46_data.a46_dummy) % sizeof(*p) == 0);		for (i= 0, p= (u16_t *)arp->a46_data.a46_dummy;			i < sizeof(arp->a46_data.a46_dummy)/sizeof(*p);			i++, p++)		{			*p= 0xdead;		}		arp->a46_dstaddr= ce->ac_ethaddr;		arp->a46_hdr= HTONS(ARP_ETHERNET);		arp->a46_pro= HTONS(ETH_IP_PROTO);		arp->a46_hln= 6;		arp->a46_pln= 4;		arp->a46_op= htons(ARP_REPLY);		if (tpa == arp_port->ap_ipaddr)		{			arp->a46_sha= arp_port->ap_ethaddr;		}		else		{			assert(cache);			arp->a46_sha= cache->ac_ethaddr;		}

⌨️ 快捷键说明

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