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

📄 eth.c

📁 Minix比较全的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*eth.cCopyright 1995 Philip Homburg*/#include "inet.h"#include "buf.h"#include "clock.h"#include "event.h"#include "osdep_eth.h"#include "type.h"#include "assert.h"#include "buf.h"#include "eth.h"#include "eth_int.h"#include "io.h"#include "sr.h"THIS_FILE#define ETH_FD_NR	(4*IP_PORT_MAX)#define EXPIRE_TIME	60*HZ	/* seconds */typedef struct eth_fd{	int ef_flags;	nwio_ethopt_t ef_ethopt;	eth_port_t *ef_port;	struct eth_fd *ef_type_next;	struct eth_fd *ef_send_next;	int ef_srfd;	acc_t *ef_rdbuf_head;	acc_t *ef_rdbuf_tail;	get_userdata_t ef_get_userdata;	put_userdata_t ef_put_userdata;	put_pkt_t ef_put_pkt;	time_t ef_exp_time;	size_t ef_write_count;	ioreq_t ef_ioctl_req;} eth_fd_t;#define EFF_FLAGS	0xf#	define EFF_EMPTY	0x0#	define EFF_INUSE	0x1#	define EFF_BUSY		0xE#		define	EFF_READ_IP	0x2#		define 	EFF_WRITE_IP	0x4#		define 	EFF_IOCTL_IP	0x8#	define EFF_OPTSET       0x10/* Note that the vh_type field is normally considered part of the ethernet * header. */typedef struct {	u16_t vh_type;	u16_t vh_vlan;} vlan_hdr_t;FORWARD int eth_checkopt ARGS(( eth_fd_t *eth_fd ));FORWARD void hash_fd ARGS(( eth_fd_t *eth_fd ));FORWARD void unhash_fd ARGS(( eth_fd_t *eth_fd ));FORWARD void eth_buffree ARGS(( int priority ));#ifdef BUF_CONSISTENCY_CHECKFORWARD void eth_bufcheck ARGS(( void ));#endifFORWARD void packet2user ARGS(( eth_fd_t *fd, acc_t *pack, time_t exp_time ));FORWARD void reply_thr_get ARGS(( eth_fd_t *eth_fd,	size_t result, int for_ioctl ));FORWARD void reply_thr_put ARGS(( eth_fd_t *eth_fd,	size_t result, int for_ioctl ));FORWARD void do_rec_conf ARGS(( eth_port_t *eth_port ));FORWARD u32_t compute_rec_conf ARGS(( eth_port_t *eth_port ));FORWARD acc_t *insert_vlan_hdr ARGS(( eth_port_t *eth_port, acc_t *pack ));PUBLIC eth_port_t *eth_port_table;PUBLIC int no_ethWritePort= 0;PRIVATE eth_fd_t eth_fd_table[ETH_FD_NR];PRIVATE ether_addr_t broadcast= { { 255, 255, 255, 255, 255, 255 } };PUBLIC void eth_prep(){	eth_port_table= alloc(eth_conf_nr * sizeof(eth_port_table[0]));}PUBLIC void eth_init(){	int i, j;	assert (BUF_S >= sizeof(nwio_ethopt_t));	assert (BUF_S >= ETH_HDR_SIZE);	/* these are in fact static assertions,					   thus a good compiler doesn't					   generate any code for this */	for (i=0; i<ETH_FD_NR; i++)		eth_fd_table[i].ef_flags= EFF_EMPTY;	for (i=0; i<eth_conf_nr; i++)	{		eth_port_table[i].etp_flags= EPF_EMPTY;		eth_port_table[i].etp_getstat= NULL;		eth_port_table[i].etp_sendq_head= NULL;		eth_port_table[i].etp_sendq_tail= NULL;		eth_port_table[i].etp_type_any= NULL;		ev_init(&eth_port_table[i].etp_sendev);		for (j= 0; j<ETH_TYPE_HASH_NR; j++)			eth_port_table[i].etp_type[j]= NULL;		for (j= 0; j<ETH_VLAN_HASH_NR; j++)			eth_port_table[i].etp_vlan_tab[j]= NULL;	}#ifndef BUF_CONSISTENCY_CHECK	bf_logon(eth_buffree);#else	bf_logon(eth_buffree, eth_bufcheck);#endif	osdep_eth_init();}PUBLIC int eth_open(port, srfd, get_userdata, put_userdata, put_pkt,	select_res)int port, srfd;get_userdata_t get_userdata;put_userdata_t put_userdata;put_pkt_t put_pkt;select_res_t select_res;{	int i;	eth_port_t *eth_port;	eth_fd_t *eth_fd;	DBLOCK(0x20, printf("eth_open (%d, %d, %lx, %lx)\n", port, srfd, 		(unsigned long)get_userdata, (unsigned long)put_userdata));	eth_port= &eth_port_table[port];	if (!(eth_port->etp_flags & EPF_ENABLED))		return EGENERIC;	for (i=0; i<ETH_FD_NR && (eth_fd_table[i].ef_flags & EFF_INUSE);		i++);	if (i>=ETH_FD_NR)	{		DBLOCK(1, printf("out of fds\n"));		return EAGAIN;	}	eth_fd= &eth_fd_table[i];	eth_fd->ef_flags= EFF_INUSE;	eth_fd->ef_ethopt.nweo_flags=NWEO_DEFAULT;	eth_fd->ef_port= eth_port;	eth_fd->ef_srfd= srfd;	assert(eth_fd->ef_rdbuf_head == NULL);	eth_fd->ef_get_userdata= get_userdata;	eth_fd->ef_put_userdata= put_userdata;	eth_fd->ef_put_pkt= put_pkt;	return i;}PUBLIC int eth_ioctl(fd, req)int fd;ioreq_t req;{	acc_t *data;	eth_fd_t *eth_fd;	eth_port_t *eth_port;	DBLOCK(0x20, printf("eth_ioctl (%d, 0x%lx)\n", fd, (unsigned long)req));	eth_fd= &eth_fd_table[fd];	eth_port= eth_fd->ef_port;	assert (eth_fd->ef_flags & EFF_INUSE);	switch (req)	{	case NWIOSETHOPT:		{			nwio_ethopt_t *ethopt;			nwio_ethopt_t oldopt, newopt;			int result;			u32_t new_en_flags, new_di_flags,				old_en_flags, old_di_flags;			data= (*eth_fd->ef_get_userdata)(eth_fd->				ef_srfd, 0, sizeof(nwio_ethopt_t), TRUE);                        ethopt= (nwio_ethopt_t *)ptr2acc_data(data);			oldopt= eth_fd->ef_ethopt;			newopt= *ethopt;			old_en_flags= oldopt.nweo_flags & 0xffff;			old_di_flags= (oldopt.nweo_flags >> 16) & 0xffff;			new_en_flags= newopt.nweo_flags & 0xffff;			new_di_flags= (newopt.nweo_flags >> 16) & 0xffff;			if (new_en_flags & new_di_flags)			{				bf_afree(data);				reply_thr_get (eth_fd, EBADMODE, TRUE);				return NW_OK;			}				/* NWEO_ACC_MASK */			if (new_di_flags & NWEO_ACC_MASK)			{				bf_afree(data);				reply_thr_get (eth_fd, EBADMODE, TRUE);				return NW_OK;			}						/* you can't disable access modes */			if (!(new_en_flags & NWEO_ACC_MASK))				new_en_flags |= (old_en_flags & NWEO_ACC_MASK);			/* NWEO_LOC_MASK */			if (!((new_en_flags | new_di_flags) & NWEO_LOC_MASK))			{				new_en_flags |= (old_en_flags & NWEO_LOC_MASK);				new_di_flags |= (old_di_flags & NWEO_LOC_MASK);			}			/* NWEO_BROAD_MASK */			if (!((new_en_flags | new_di_flags) & NWEO_BROAD_MASK))			{				new_en_flags |= (old_en_flags & NWEO_BROAD_MASK);				new_di_flags |= (old_di_flags & NWEO_BROAD_MASK);			}			/* NWEO_MULTI_MASK */			if (!((new_en_flags | new_di_flags) & NWEO_MULTI_MASK))			{				new_en_flags |= (old_en_flags & NWEO_MULTI_MASK);				new_di_flags |= (old_di_flags & NWEO_MULTI_MASK);				newopt.nweo_multi= oldopt.nweo_multi;			}			/* NWEO_PROMISC_MASK */			if (!((new_en_flags | new_di_flags) & NWEO_PROMISC_MASK))			{				new_en_flags |= (old_en_flags & NWEO_PROMISC_MASK);				new_di_flags |= (old_di_flags & NWEO_PROMISC_MASK);			}			/* NWEO_REM_MASK */			if (!((new_en_flags | new_di_flags) & NWEO_REM_MASK))			{				new_en_flags |= (old_en_flags & NWEO_REM_MASK);				new_di_flags |= (old_di_flags & NWEO_REM_MASK);				newopt.nweo_rem= oldopt.nweo_rem;			}			/* NWEO_TYPE_MASK */			if (!((new_en_flags | new_di_flags) & NWEO_TYPE_MASK))			{				new_en_flags |= (old_en_flags & NWEO_TYPE_MASK);				new_di_flags |= (old_di_flags & NWEO_TYPE_MASK);				newopt.nweo_type= oldopt.nweo_type;			}			/* NWEO_RW_MASK */			if (!((new_en_flags | new_di_flags) & NWEO_RW_MASK))			{				new_en_flags |= (old_en_flags & NWEO_RW_MASK);				new_di_flags |= (old_di_flags & NWEO_RW_MASK);			}			if (eth_fd->ef_flags & EFF_OPTSET)				unhash_fd(eth_fd);			newopt.nweo_flags= ((unsigned long)new_di_flags << 16) |				new_en_flags;			eth_fd->ef_ethopt= newopt;			result= eth_checkopt(eth_fd);			if (result<0)				eth_fd->ef_ethopt= oldopt;			else			{				unsigned long opt_flags;				unsigned changes;				opt_flags= oldopt.nweo_flags ^					eth_fd->ef_ethopt.nweo_flags;				changes= ((opt_flags >> 16) | opt_flags) &					0xffff;				if (changes & (NWEO_BROAD_MASK |					NWEO_MULTI_MASK | NWEO_PROMISC_MASK))				{					do_rec_conf(eth_port);				}			}			if (eth_fd->ef_flags & EFF_OPTSET)				hash_fd(eth_fd);			bf_afree(data);			reply_thr_get (eth_fd, result, TRUE);			return NW_OK;			}	case NWIOGETHOPT:		{			nwio_ethopt_t *ethopt;			acc_t *acc;			int result;			acc= bf_memreq(sizeof(nwio_ethopt_t));			ethopt= (nwio_ethopt_t *)ptr2acc_data(acc);			*ethopt= eth_fd->ef_ethopt;			result= (*eth_fd->ef_put_userdata)(eth_fd->				ef_srfd, 0, acc, TRUE);			if (result >= 0)				reply_thr_put(eth_fd, NW_OK, TRUE);			return result;		}	case NWIOGETHSTAT:		{			nwio_ethstat_t *ethstat;			acc_t *acc;			int result;			assert (sizeof(nwio_ethstat_t) <= BUF_S);			eth_port= eth_fd->ef_port;			if (!(eth_port->etp_flags & EPF_ENABLED))			{				reply_thr_put(eth_fd, EGENERIC, TRUE);				return NW_OK;			}			if (!(eth_port->etp_flags & EPF_GOT_ADDR))			{				printf(				"eth_ioctl: suspending NWIOGETHSTAT ioctl\n");				eth_fd->ef_ioctl_req= req;				assert(!(eth_fd->ef_flags & EFF_IOCTL_IP));				eth_fd->ef_flags |= EFF_IOCTL_IP;				return NW_SUSPEND;			}			if (eth_port->etp_getstat)			{				printf(	"eth_ioctl: pending eth_get_stat request, suspending caller\n");				assert(!(eth_fd->ef_flags & EFF_IOCTL_IP));				eth_fd->ef_flags |= EFF_IOCTL_IP;				return NW_SUSPEND;			}			acc= bf_memreq(sizeof(nwio_ethstat_t));			compare (bf_bufsize(acc), ==, sizeof(*ethstat));			ethstat= (nwio_ethstat_t *)ptr2acc_data(acc);			ethstat->nwes_addr= eth_port->etp_ethaddr;			if (!eth_port->etp_vlan)			{				result= eth_get_stat(eth_port,					&ethstat->nwes_stat);				if (result == SUSPEND)				{					printf(				"eth_ioctl: eth_get_stat returned SUSPEND\n");					eth_fd->ef_ioctl_req= req;					assert(!(eth_fd->ef_flags &						EFF_IOCTL_IP));					eth_fd->ef_flags |= EFF_IOCTL_IP;printf("eth_ioctl: setting etp_getstat in port %d to %p\n",	eth_port-eth_port_table, acc);					eth_port->etp_getstat= acc;					acc= NULL;					return NW_SUSPEND;				}				if (result != NW_OK)				{					bf_afree(acc);					reply_thr_put(eth_fd, result, TRUE);					return NW_OK;				}			}			else			{				/* No statistics */				memset(&ethstat->nwes_stat, '\0',					sizeof(ethstat->nwes_stat));			}			result= (*eth_fd->ef_put_userdata)(eth_fd->				ef_srfd, 0, acc, TRUE);			if (result >= 0)				reply_thr_put(eth_fd, NW_OK, TRUE);			return result;		}	default:		break;	}	reply_thr_put(eth_fd, EBADIOCTL, TRUE);	return NW_OK;}PUBLIC int eth_write(fd, count)int fd;size_t count;{	eth_fd_t *eth_fd;	eth_port_t *eth_port, *rep;	acc_t *user_data;	int r;	eth_fd= &eth_fd_table[fd];	eth_port= eth_fd->ef_port;	if (!(eth_fd->ef_flags & EFF_OPTSET))	{		reply_thr_get (eth_fd, EBADMODE, FALSE);		return NW_OK;	}	assert (!(eth_fd->ef_flags & EFF_WRITE_IP));	eth_fd->ef_write_count= count;	if (eth_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY)		count += ETH_HDR_SIZE;	if (count<ETH_MIN_PACK_SIZE || count>ETH_MAX_PACK_SIZE)	{		DBLOCK(1, printf("illegal packetsize (%d)\n",count));		reply_thr_get (eth_fd, EPACKSIZE, FALSE);		return NW_OK;	}	eth_fd->ef_flags |= EFF_WRITE_IP;	/* Enqueue at the real ethernet port */	rep= eth_port->etp_vlan_port;	if (!rep)		rep= eth_port;	if (rep->etp_wr_pack)	{		eth_fd->ef_send_next= NULL;		if (rep->etp_sendq_head)			rep->etp_sendq_tail->ef_send_next= eth_fd;		else			rep->etp_sendq_head= eth_fd;		rep->etp_sendq_tail= eth_fd;		return NW_SUSPEND;	}	user_data= (*eth_fd->ef_get_userdata)(eth_fd->ef_srfd, 0,		eth_fd->ef_write_count, FALSE);	if (!user_data)	{		eth_fd->ef_flags &= ~EFF_WRITE_IP;		reply_thr_get (eth_fd, EFAULT, FALSE);		return NW_OK;	}	r= eth_send(fd, user_data, eth_fd->ef_write_count);	assert(r == NW_OK);	eth_fd->ef_flags &= ~EFF_WRITE_IP;	reply_thr_get(eth_fd, eth_fd->ef_write_count, FALSE);	return NW_OK;}PUBLIC int eth_send(fd, data, data_len)int fd;acc_t *data;size_t data_len;{	eth_fd_t *eth_fd;	eth_port_t *eth_port, *rep;	eth_hdr_t *eth_hdr;	acc_t *eth_pack;	unsigned long nweo_flags;	size_t count;	ev_arg_t ev_arg;	eth_fd= &eth_fd_table[fd];	eth_port= eth_fd->ef_port;	if (!(eth_fd->ef_flags & EFF_OPTSET))		return EBADMODE;	count= data_len;	if (eth_fd->ef_ethopt.nweo_flags & NWEO_RWDATONLY)		count += ETH_HDR_SIZE;	if (count<ETH_MIN_PACK_SIZE || count>ETH_MAX_PACK_SIZE)	{		DBLOCK(1, printf("illegal packetsize (%d)\n",count));		return EPACKSIZE;	}	rep= eth_port->etp_vlan_port;	if (!rep)		rep= eth_port;	if (rep->etp_wr_pack)		return NW_WOULDBLOCK;		nweo_flags= eth_fd->ef_ethopt.nweo_flags;	if (nweo_flags & NWEO_RWDATONLY)	{		eth_pack= bf_memreq(ETH_HDR_SIZE);		eth_pack->acc_next= data;	}	else		eth_pack= bf_packIffLess(data, ETH_HDR_SIZE);	eth_hdr= (eth_hdr_t *)ptr2acc_data(eth_pack);	if (nweo_flags & NWEO_REMSPEC)		eth_hdr->eh_dst= eth_fd->ef_ethopt.nweo_rem;	if (!(eth_port->etp_flags & EPF_GOT_ADDR))	{		/* No device, discard packet */		bf_afree(eth_pack);		return NW_OK;	}	if (!(nweo_flags & NWEO_EN_PROMISC))		eth_hdr->eh_src= eth_port->etp_ethaddr;	if (nweo_flags & NWEO_TYPESPEC)		eth_hdr->eh_proto= eth_fd->ef_ethopt.nweo_type;	if (eth_addrcmp(eth_hdr->eh_dst, eth_port->etp_ethaddr) == 0)	{		/* Local loopback. */		eth_port->etp_wr_pack= eth_pack;		ev_arg.ev_ptr= eth_port;		ev_enqueue(&eth_port->etp_sendev, eth_loop_ev, ev_arg);		return NW_OK;	}	if (rep != eth_port)	{		eth_pack= insert_vlan_hdr(eth_port, eth_pack);		if (!eth_pack)		{			/* Packet is silently discarded */			return NW_OK;		}	}	eth_write_port(rep, eth_pack);	return NW_OK;}PUBLIC int eth_read (fd, count)int fd;size_t count;{	eth_fd_t *eth_fd;	acc_t *pack;	eth_fd= &eth_fd_table[fd];	if (!(eth_fd->ef_flags & EFF_OPTSET))	{		reply_thr_put(eth_fd, EBADMODE, FALSE);		return NW_OK;	}	if (count < ETH_MAX_PACK_SIZE)	{		reply_thr_put(eth_fd, EPACKSIZE, FALSE);		return NW_OK;	}	assert(!(eth_fd->ef_flags & EFF_READ_IP));	eth_fd->ef_flags |= EFF_READ_IP;	while (eth_fd->ef_rdbuf_head)	{		pack= eth_fd->ef_rdbuf_head;		eth_fd->ef_rdbuf_head= pack->acc_ext_link;		if (get_time() <= eth_fd->ef_exp_time)		{			packet2user(eth_fd, pack, eth_fd->ef_exp_time);			if (!(eth_fd->ef_flags & EFF_READ_IP))				return NW_OK;		}		else			bf_afree(pack);	}	return NW_SUSPEND;}PUBLIC int eth_cancel(fd, which_operation)int fd;int which_operation;{	eth_fd_t *eth_fd, *prev, *loc_fd;	eth_port_t *eth_port;	DBLOCK(2, printf("eth_cancel (%d)\n", fd));	eth_fd= &eth_fd_table[fd];	switch (which_operation)	{	case SR_CANCEL_READ:		assert (eth_fd->ef_flags & EFF_READ_IP);		eth_fd->ef_flags &= ~EFF_READ_IP;		reply_thr_put(eth_fd, EINTR, FALSE);		break;	case SR_CANCEL_WRITE:		assert (eth_fd->ef_flags & EFF_WRITE_IP);		eth_fd->ef_flags &= ~EFF_WRITE_IP;		/* Remove fd from send queue */		eth_port= eth_fd->ef_port;		if (eth_port->etp_vlan_port)			eth_port= eth_port->etp_vlan_port;		for (prev= 0, loc_fd= eth_port->etp_sendq_head; loc_fd != NULL;			prev= loc_fd, loc_fd= loc_fd->ef_send_next)		{			if (loc_fd == eth_fd)				break;		}		assert(loc_fd == eth_fd);		if (prev == NULL)			eth_port->etp_sendq_head= loc_fd->ef_send_next;		else			prev->ef_send_next= loc_fd->ef_send_next;		if (loc_fd->ef_send_next == NULL)			eth_port->etp_sendq_tail= prev;					reply_thr_get(eth_fd, EINTR, FALSE);		break;	case SR_CANCEL_IOCTL:		assert (eth_fd->ef_flags & EFF_IOCTL_IP);		eth_fd->ef_flags &= ~EFF_IOCTL_IP;		reply_thr_get(eth_fd, EINTR, TRUE);		break;	default:		ip_panic(( "got unknown cancel request" ));	}	return NW_OK;

⌨️ 快捷键说明

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