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

📄 arp.c

📁 MINIX系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
arp.c
*/

#include "inet.h"

#include "arp.h"
#include "assert.h"
#include "buf.h"
#include "clock.h"
#include "eth.h"
#include "io.h"
#include "sr.h"
#include "type.h"

INIT_PANIC();

#define ARP_PORT_NR	1
#define ARP_CACHE1_NR	8
#define ARP_CACHE2_NR	8
#define ARP_CACHE3_NR	16
#define ARP_CACHE_NR	(ARP_CACHE1_NR+ARP_CACHE2_NR+ARP_CACHE3_NR)
#define ARP_TYPE1	1
#define ARP_TYPE2	2
#define ARP_TYPE3	3

#define MAX_RARP_RETRIES	5
#define MAX_ARP_RETRIES		5
#define RARP_TIMEOUT		(1*HZ)
#define ARP_TIMEOUT		(HZ/2+1)	/* .5 seconds */
#define ARP_EXP_TIME		(20L*60L*HZ)	/* 20 minutes */
#define ARP_NOTRCH_EXP_TIME	(2L*60L*HZ)	/* 2 minutes */
#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, rarp46_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_tpa

typedef struct arp_cache
{
	int ac_flags;
	int ac_type;
	ether_addr_t ac_ethaddr;
	ipaddr_t ac_ipaddr;
	int ac_eth_port;
	time_t ac_expire;
	time_t ac_lastuse;
} arp_cache_t;

#define ACF_EMPTY	0
#define ACF_NETREQ	1
#define ACF_NOTRCH	2

typedef struct arp_port
{
	int ap_flags;
	int ap_state;
	int ap_eth_port;
	int ap_eth_fd;
	int ap_rarp_retries;
	ether_addr_t ap_ethaddr;
	ipaddr_t ap_ipaddr;
	timer_t ap_timer;
	ether_addr_t ap_write_ethaddr;
	ipaddr_t ap_write_ipaddr;
	int ap_write_code;
	ipaddr_t ap_req_ipaddr;
	arp_req_func_t ap_req_func;
	int ap_req_ref;
	int ap_req_count;
	rarp_func_t ap_rarp_func;
	int ap_rarp_ref;
} arp_port_t;

#define APF_EMPTY	0
#define APF_RARP_RD_IP	0x1
#define APF_RARP_RD_SP	0x2
#define APF_ARP_RD_IP	0x4
#define APF_ARP_RD_SP	0x8
#define APF_ARP_WR_IP	0x10
#define APF_ARP_WR_SP	0x20
#define APF_INADDR_SET	0x100
#define APF_MORE2WRITE	0x200
#define APF_CLIENTREQ	0x400
#define APF_RARPREQ	0x800
#define APF_CLIENTWRITE	0x1000

#define APS_EMPTY	0
#define APS_STATMASK	0xff
#define		APS_GETADDR	0x1
#define		APS_RARPPROTO	0x2
#define		APS_RARPWRITE	0x4
#define		APS_RARPWAIT	0x8
#define		APS_ARPSTART	0x10
#define		APS_ARPPROTO	0x20
#define		APS_ARPMAIN	0x40
#define		APS_ERROR	0x80
#define APS_SUSPEND	0x400

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 *port ));
FORWARD void arp_timeout ARGS(( int fd, timer_t *timer ));
FORWARD void rarp_timeout ARGS(( int fd, timer_t *timer ));
FORWARD void ipaddr_set ARGS(( arp_port_t *port ));
FORWARD void setup_write ARGS(( arp_port_t *port ));
FORWARD void setup_read ARGS(( arp_port_t *port ));
FORWARD void process_arp_req ARGS(( arp_port_t *port, acc_t *data ));
FORWARD void client_reply ARGS(( arp_port_t *port,
	ether_addr_t *ethaddr ));
FORWARD arp_cache_t *find_cache_ent ARGS(( int eth_port, ipaddr_t ipaddr,
	int level, arp_cache_t **new_ent ));
FORWARD void rarp_read_setup ARGS(( arp_port_t *port ));
FORWARD void print_arp_cache ARGS(( void ));

PRIVATE arp_port_t arp_port_table[ARP_PORT_NR];
PRIVATE arp_port_t *arp_port;
PRIVATE	arp_cache_t arp_cache[ARP_CACHE_NR];

PUBLIC void arp_init()
{
	int i;

	assert (BUF_S >= sizeof(struct nwio_ethstat));
	assert (BUF_S >= sizeof(struct nwio_ethopt));
	assert (BUF_S >= sizeof(rarp46_t));
	assert (BUF_S >= sizeof(arp46_t));
	arp_port_table[0].ap_eth_port= ETH0;

	for (i=0, arp_port= arp_port_table; i<ARP_PORT_NR; i++, arp_port++)
	{
		arp_port->ap_state= APS_EMPTY;
		arp_port->ap_flags= APF_EMPTY;
		arp_main(arp_port);
	}
}

PRIVATE void arp_main(port)
arp_port_t *port;
{
	int result;

#if DEBUG & 256
 { where(); printf("in arp_main with status: %d\n", port->ap_state &
	APS_STATMASK); }
#endif
	switch (port->ap_state & APS_STATMASK)
	{
	case APS_EMPTY:
		port->ap_rarp_retries= 0;
		port->ap_eth_fd= eth_open(port->ap_eth_port,
			port-arp_port_table, arp_getdata, arp_putdata);

		if (port->ap_eth_fd<0)
		{
	printf("arp.c: unable to open ethernet\n");
			return;
		}

		port->ap_state= (port->ap_state &
			 ~(APS_STATMASK|APS_SUSPEND)) | APS_GETADDR;

		result= eth_ioctl (port->ap_eth_fd, NWIOGETHSTAT);

		if (result==NW_SUSPEND)
			port->ap_state |= APS_SUSPEND;

		if (result<0)
		{
#if DEBUG
 if (result != NW_SUSPEND)
 { where(); printf("arp.c: eth_ioctl(..,NWIOGETHSTAT)=%d\n", result); }
#endif
			return;
		}
		if ((port->ap_state & APS_STATMASK) != APS_GETADDR)
			return;
		/* drop through */
	case APS_GETADDR:
#if DEBUG & 256
 { where(); printf("in arp_main with status: %d\n", port->ap_state & APS_STATMASK); }
#endif
		port->ap_state= (port->ap_state &
			~(APS_STATMASK|APS_SUSPEND)) | APS_RARPPROTO;

		result= eth_ioctl (port->ap_eth_fd, NWIOSETHOPT);

		if (result==NW_SUSPEND)
			port->ap_state |= APS_SUSPEND;

		if (result<0)
		{
#if DEBUG
 if (result != NW_SUSPEND)
 { printf("arp.c: eth_ioctl(..,NWIOSETHOPT)=%d\n", result); }
#endif
			return;
		}
		if ((port->ap_state & APS_STATMASK) != APS_RARPPROTO)
			return;
		/* drop through */
	case APS_RARPWAIT:
#if DEBUG & 256
 { where(); printf("in arp_main with status: %d\n",
	port->ap_state & APS_STATMASK); }
#endif
		if (port->ap_flags & APF_INADDR_SET)
		{
			port->ap_state= (port->ap_state &
				~(APS_STATMASK|APS_SUSPEND)) | APS_ARPSTART;
			arp_main(port);
			return;
		}
		/* drop through */
	case APS_RARPPROTO:
#if DEBUG & 256
 { where(); printf("in arp_main with status: %d\n",
	port->ap_state & APS_STATMASK); }
#endif
		rarp_read_setup(port);
		port->ap_state= (port->ap_state &
			~(APS_STATMASK|APS_SUSPEND)) | APS_RARPWRITE;
#if DEBUG & 256
 { where(); printf("doing eth_write\n"); }
#endif
		result= eth_write (port->ap_eth_fd, sizeof(rarp46_t));
		if (result == NW_SUSPEND)
			port->ap_state |= APS_SUSPEND;
		if (result<0)
		{
#if DEBUG & 256
 if (result != NW_SUSPEND)
 { where();  printf("arp.c: eth_write(..,%d)=%d\n", sizeof(rarp46_t), result); }
#endif
			return;
		}
		if ((port->ap_state & APS_STATMASK) != APS_RARPWRITE)
			return;
		/* drop through */
	case APS_RARPWRITE:
#if DEBUG & 256
 { where(); printf("in arp_main with status: %d\n",
	port->ap_state & APS_STATMASK); }
#endif
		port->ap_state= (port->ap_state &
			~(APS_STATMASK|APS_SUSPEND)) | APS_RARPWAIT;
		if (port->ap_rarp_retries>=MAX_RARP_RETRIES)
			return;
#if DEBUG & 256
 { where(); printf("port->ap_rarp_retries= %d\n",
	port->ap_rarp_retries); }
#endif
		port->ap_rarp_retries++;
		clck_timer(&port->ap_timer, get_time() + RARP_TIMEOUT,
			rarp_timeout, port-arp_port_table);
		return;
	case APS_ARPSTART:
#if DEBUG & 256
 { where(); printf("in arp_main with status: %d\n",
	port->ap_state & APS_STATMASK); }
#endif
		if (port->ap_flags & APF_RARP_RD_IP)
		{
			eth_cancel(port->ap_eth_fd, SR_CANCEL_READ);
			port->ap_flags &= ~(APF_RARP_RD_IP|APF_RARP_RD_SP);
		}
		port->ap_state= (port->ap_state &
			~(APS_STATMASK|APS_SUSPEND)) | APS_ARPPROTO;

		{
			arp_cache_t *cache;
			int i;

			cache= arp_cache;
			for (i=0; i<ARP_CACHE_NR; i++, cache++)
			{
				cache->ac_flags= ACF_EMPTY;
				cache->ac_expire= 0;
				cache->ac_lastuse= 0;
			}

			cache= arp_cache;
			for (i=0; i<ARP_CACHE1_NR; i++, cache++)
				cache->ac_type= 1;
			for (i=0; i<ARP_CACHE2_NR; i++, cache++)
				cache->ac_type= 2;
			for (i=0; i<ARP_CACHE3_NR; i++, cache++)
				cache->ac_type= 3;
		}
		result= eth_ioctl (port->ap_eth_fd, NWIOSETHOPT);

		if (result==NW_SUSPEND)
			port->ap_state |= APS_SUSPEND;

		if (result<0)
		{
#if DEBUG
 { where(); printf("arp.c: /* arp */ eth_ioctl(..,NWIOSETHOPT)=%d\n",
	result); }
#endif
			return;
		}
		if ((port->ap_state & APS_STATMASK) != APS_ARPPROTO)
			return;
		/* drop through */
	case APS_ARPPROTO:
#if DEBUG & 256
 { where(); printf("in arp_main with status: %d\n",
	port->ap_state & APS_STATMASK); }
#endif
		port->ap_state= (port->ap_state &
			~(APS_STATMASK|APS_SUSPEND)) | APS_ARPMAIN;
		if (port->ap_flags & APF_MORE2WRITE)
			setup_write(port);
		setup_read(port);
		return;
	default:
		ip_panic((
		 "arp_main(&arp_port_table[%d]) called but ap_state=0x%x\n",
			port-arp_port_table, 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 *port;
	rarp46_t *rarp;
	arp46_t *arp;
	acc_t *data;
	int result;

#if DEBUG & 256
 { where(); printf("arp_getdata (fd= %d, offset= %d, count= %d)\n", fd,
	offset, count); }
#endif
	port= &arp_port_table[fd];

	switch (port->ap_state & APS_STATMASK)
	{
	case APS_RARPPROTO:
		if (!count)
		{
			result= (int)offset;
			if (result<0)
			{
				port->ap_state= (port->ap_state &
					 ~(APS_STATMASK|APS_SUSPEND))|
					 APS_ERROR;
				break;
			}
			if (port->ap_state & APS_SUSPEND)
				arp_main(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_TYPESPEC;
			ethopt->nweo_type= htons(ETH_RARP_PROTO);
			return acc;
		}
	case APS_RARPWRITE:
		if (!count)
		{
			result= (int)offset;
			if (result<0)
			{
#if DEBUG
 if (result != NW_SUSPEND)
 { where(); printf("arp.c: write error on port %d: error %d\n", fd, result); }
#endif
				port->ap_state= (port->ap_state &
					 ~(APS_STATMASK|APS_SUSPEND))|
					 APS_ERROR;
				break;
			}
			if (port->ap_state & APS_SUSPEND)
				arp_main(port);
			return NW_OK;
		}
		assert (offset+count <= sizeof(rarp46_t));
		data= bf_memreq(sizeof(rarp46_t));
		rarp= (rarp46_t *)ptr2acc_data(data);
		data->acc_offset += offset;
		data->acc_length= count;
		rarp->a46_dstaddr.ea_addr[0]= 0xff;
		rarp->a46_dstaddr.ea_addr[1]= 0xff;
		rarp->a46_dstaddr.ea_addr[2]= 0xff;
		rarp->a46_dstaddr.ea_addr[3]= 0xff;
		rarp->a46_dstaddr.ea_addr[4]= 0xff;
		rarp->a46_dstaddr.ea_addr[5]= 0xff;
		rarp->a46_hdr= htons(ARP_ETHERNET);
		rarp->a46_pro= htons(ETH_IP_PROTO);
		rarp->a46_hln= 6;
		rarp->a46_pln= 4;
		rarp->a46_op= htons(RARP_REQUEST);
		rarp->a46_sha= port->ap_ethaddr;
		rarp->a46_tha= port->ap_ethaddr;
		return data;
	case APS_ARPPROTO:
		if (!count)
		{
			result= (int)offset;
			if (result<0)
			{
				port->ap_state= (port->ap_state &
					 ~(APS_STATMASK|APS_SUSPEND))|
					 APS_ERROR;
				break;
			}
			if (port->ap_state & APS_SUSPEND)
				arp_main(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 (port->ap_flags & APF_ARP_WR_IP);
		if (!count)
		{
			result= (int)offset;
			if (result<0)
			{
#if DEBUG
 if (result != NW_SUSPEND)
 { where(); printf("arp.c: write error on port %d: error %d\n", fd, result); }
#endif
				port->ap_state= (port->ap_state &
					 ~(APS_STATMASK|APS_SUSPEND))|
					 APS_ERROR;
				break;
			}
			port->ap_flags &= ~APF_ARP_WR_IP;
			if (port->ap_flags & APF_ARP_WR_SP)
				setup_write(port);
			return NW_OK;
		}
		assert (offset+count <= sizeof(arp46_t));
		data= bf_memreq(sizeof(arp46_t));
		arp= (arp46_t *)ptr2acc_data(data);
		data->acc_offset += offset;
		data->acc_length= count;
		if (port->ap_write_code == ARP_REPLY)
			arp->a46_dstaddr= port->ap_write_ethaddr;
		else
		{
			arp->a46_dstaddr.ea_addr[0]= 0xff;
			arp->a46_dstaddr.ea_addr[1]= 0xff;
			arp->a46_dstaddr.ea_addr[2]= 0xff;
			arp->a46_dstaddr.ea_addr[3]= 0xff;
			arp->a46_dstaddr.ea_addr[4]= 0xff;
			arp->a46_dstaddr.ea_addr[5]= 0xff;
		}
		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(port->ap_write_code);
		arp->a46_sha= port->ap_ethaddr;
		memcpy (arp->a46_spa, &port->ap_ipaddr, sizeof(ipaddr_t));
		arp->a46_tha= port->ap_write_ethaddr;
		memcpy (arp->a46_tpa, &port->ap_write_ipaddr, sizeof(ipaddr_t));
		return data;
	default:
		printf("arp_getdata(%d, 0x%d, 0x%d) called but ap_state=0x%x\n",
			fd, offset, count, 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 *port;
	int result;
	struct nwio_ethstat *ethstat;
	rarp46_t *rarp;

#if DEBUG & 256
 { where(); printf("arp_putdata (fd= %d, offset= %d, data= 0x%x)\n",
	fd, offset, data); }
#endif
	port= &arp_port_table[fd];

	if (port->ap_flags & APF_ARP_RD_IP)
	{
		if (!data)
		{
			result= (int)offset;
			if (result<0)
			{
#if DEBUG
 if (result != NW_SUSPEND)
 { where(); printf("arp.c: read error on port %d: error %d\n", fd, result); }
#endif
				return NW_OK;
			}
			if (port->ap_flags & APF_ARP_RD_SP)
			{
				port->ap_flags &= ~(APF_ARP_RD_IP|
					APF_ARP_RD_SP);
				setup_read(port);
			}
			else
				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))
			process_arp_req(port,data);
		bf_afree(data);
		return NW_OK;
	}
	if (port->ap_flags & APF_RARP_RD_IP)
	{
		if (!data)
		{
			result= (int)offset;
			if (result<0)
			{

⌨️ 快捷键说明

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