📄 eth.c
字号:
/*
eth.c
*/
#include "inet.h"
#include "buf.h"
#include "clock.h"
#include "osdep_eth.h"
#include "assert.h"
#include "buf.h"
#include "eth.h"
#include "eth_int.h"
#include "io.h"
#include "sr.h"
#include "type.h"
INIT_PANIC();
#define ETH_FD_NR 32
#define EXPIRE_TIME 60*HZ /* seconds */
typedef struct eth_fd
{
int ef_flags;
eth_port_t *ef_port;
int ef_srfd;
get_userdata_t ef_get_userdata;
put_userdata_t ef_put_userdata;
nwio_ethopt_t ef_ethopt;
size_t ef_write_count;
acc_t *ef_rd_buf;
acc_t *ef_rd_tail;
time_t ef_exp_tim;
int ef_pack_stat;
} eth_fd_t;
#define EFF_FLAGS 0xf
# define EFF_EMPTY 0x0
# define EFF_INUSE 0x1
# define EFF_BUSY 0x6
# define EFF_READ_IP 0x2
# define EFF_WRITE_IP 0x4
# define EFF_OPTSET 0x8
FORWARD int eth_checkopt ARGS(( eth_fd_t *eth_fd ));
FORWARD void eth_buffree ARGS(( int priority, size_t reqsize ));
FORWARD int ok_for_me ARGS(( eth_fd_t *fd, acc_t *pack ));
FORWARD int packet2user ARGS(( eth_fd_t *fd ));
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 restart_write_fd ARGS(( eth_fd_t *eth_fd ));
PUBLIC eth_port_t eth_port_table[ETH_PORT_NR];
PRIVATE eth_fd_t eth_fd_table[ETH_FD_NR];
/* PRIVATE message mess, repl_mess; */
PUBLIC void eth_init()
{
int i;
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_PORT_NR; i++)
eth_port_table[i].etp_flags= EFF_EMPTY;
bf_logon(eth_buffree);
eth_init0();
/* eth_init1(); etc */
}
PUBLIC int eth_open(port, srfd, get_userdata, put_userdata)
int port, srfd;
get_userdata_t get_userdata;
put_userdata_t put_userdata;
{
int i;
eth_port_t *eth_port;
eth_fd_t *eth_fd;
#if DEBUG & 256
{ where(); printf("eth_open (%d, ...)\n", port); }
#endif
eth_port= ð_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)
{
#if DEBUG
{ where(); printf("out of fds\n"); }
#endif
return EOUTOFBUFS;
}
eth_fd= ð_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;
eth_fd->ef_rd_buf= 0;
eth_fd->ef_get_userdata= get_userdata;
eth_fd->ef_put_userdata= put_userdata;
return i;
}
PUBLIC int eth_ioctl(fd, req)
int fd;
int req;
{
acc_t *data;
int type;
eth_fd_t *eth_fd;
eth_port_t *eth_port;
#if DEBUG & 256
{ where(); printf("eth_ioctl (%d, ...)\n", fd); }
#endif
eth_fd= ð_fd_table[fd];
eth_port= eth_fd->ef_port;
type= req & IOCTYPE_MASK;
assert (eth_fd->ef_flags & EFF_INUSE);
switch (type)
{
case NWIOSETHOPT & IOCTYPE_MASK:
{
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;
u32_t flags;
eth_fd_t *loc_fd;
int i;
if (req != NWIOSETHOPT)
break;
#if DEBUG & 256
{ where(); printf("calling *get_userdata\n"); }
#endif
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;
#if DEBUG & 256
{ where(); printf("newopt.nweo_flags= 0x%x\n", newopt.nweo_flags); }
#endif
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);
}
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))
{
flags= NWEO_NOFLAGS;
for (i=0, loc_fd= eth_fd_table;
i<ETH_FD_NR; i++, loc_fd++)
{
if (!(loc_fd->ef_flags |
~(EFF_INUSE | EFF_OPTSET)))
continue;
if (loc_fd->ef_port
!= eth_port)
continue;
flags |= loc_fd->ef_ethopt.
nweo_flags;
}
eth_set_rec_conf(eth_port, flags);
}
}
bf_afree(data);
reply_thr_get (eth_fd, result, TRUE);
return NW_OK;
}
case NWIOGETHOPT & IOCTYPE_MASK:
{
nwio_ethopt_t *ethopt;
acc_t *acc;
int result;
if (req != NWIOGETHOPT)
break;
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 & IOCTYPE_MASK:
{
nwio_ethstat_t *ethstat;
acc_t *acc;
int result;
assert (sizeof(nwio_ethstat_t) <= BUF_S);
if (req != NWIOGETHSTAT)
break;
eth_port= eth_fd->ef_port;
if (!(eth_port->etp_flags & EPF_ENABLED))
{
reply_thr_put(eth_fd, EGENERIC, TRUE);
return NW_OK;
}
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;
result= eth_get_stat(eth_port, ðstat->nwes_stat);
assert (result == 0);
#if DEBUG & 256
{ where(); printf("returning NW_OK\n"); }
#endif
compare (bf_bufsize(acc), ==, sizeof(*ethstat));
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;
#if DEBUG & 256
{ where(); printf("eth_write (%d, ...)\n", fd); }
#endif
eth_fd= ð_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)
{
#if DEBUG
{ where(); printf("illegal packetsize (%d)\n",count); }
#endif
reply_thr_get (eth_fd, EPACKSIZE, FALSE);
return NW_OK;
}
eth_fd->ef_flags |= EFF_WRITE_IP;
restart_write_fd(eth_fd);
if (eth_fd->ef_flags & EFF_WRITE_IP)
return NW_SUSPEND;
else
return NW_OK;
}
PUBLIC int eth_read (fd, count)
int fd;
size_t count;
{
eth_fd_t *eth_fd;
acc_t *acc, *acc2;
#if DEBUG & 256
{ where(); printf("eth_read (%d, ...)\n", fd); }
#endif
eth_fd= ð_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;
}
if (eth_fd->ef_rd_buf)
{
if (get_time() <= eth_fd->ef_exp_tim)
return packet2user (eth_fd);
for (acc= eth_fd->ef_rd_buf; acc;)
{
acc2= acc->acc_ext_link;
bf_afree(acc);
acc= acc2;
}
eth_fd->ef_rd_buf= 0;
}
eth_fd->ef_flags |= EFF_READ_IP;
#if DEBUG & 256
{ where(); printf("eth_fd_table[%d].ef_flags= 0x%x\n",
eth_fd-eth_fd_table, eth_fd->ef_flags); }
#endif
return NW_SUSPEND;
}
PUBLIC int eth_cancel(fd, which_operation)
int fd;
int which_operation;
{
eth_fd_t *eth_fd;
#if DEBUG & 2
{ where(); printf("eth_cancel (%d)\n", fd); }
#endif
eth_fd= ð_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;
reply_thr_get(eth_fd, EINTR, FALSE);
break;
default:
ip_panic(( "got unknown cancel request" ));
}
return NW_OK;
}
PUBLIC void eth_close(fd)
int fd;
{
eth_fd_t *eth_fd;
acc_t *acc, *acc2;
#if DEBUG
{ where(); printf("eth_close (%d)\n", fd); }
#endif
eth_fd= ð_fd_table[fd];
assert (eth_fd->ef_flags & EFF_INUSE);
eth_fd->ef_flags= EFF_EMPTY;
for (acc= eth_fd->ef_rd_buf; acc;)
{
acc2= acc->acc_ext_link;
bf_afree(acc);
acc= acc2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -