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

📄 网口程序实例.txt

📁 关于数据发送方面和接收差不多,在上层协议放置好数据到mbuf链后,调用el_start函数,该函数把mbuf链中 的数据放置到本块网卡的发送队列缓冲el_pktbuf中,然后再调用el_xmit函
💻 TXT
📖 第 1 页 / 共 3 页
字号:
if (bpf)             bpf为真,即加入了BSD包过滤 
bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); 
if (ng_ether_attach_p != NULL) 
(*ng_ether_attach_p)(ifp); 
} 

*/ 
printf("el%d: 3c501 address %6D\n",idev->;id_unit, 
  sc->;arpcom.ac_enaddr, ":"); 

dprintf(("el_attach() finished.\n")); 
return(1); 
} 

/* 该例程重设接口. 在el_watchdog()中调用,因为watchdog不在本驱动程序中支持,所以从不被调用*/ 
static void  
el_reset(xsc)/*上面的一个函数,重设硬件*/ 
void *xsc; 
{ 
struct el_softc *sc = xsc; 
int s; 

dprintf(("elreset()\n")); 
s = splimp();/*关网络中断*/ 
el_stop(sc);/*下面的一个函数*/ 
el_init(sc);/*重新初始化卡*/ 
splx(s);/*开网络中断*/ 
} 
/*停止接口,在el_ioctl()和el_reset()中调用*/ 
static void el_stop(xsc) 
void *xsc; 
{ 
struct el_softc *sc = xsc; 

outb(sc->;el_base+EL_AC,0);/*用0写辅助命令寄存器*/ 
} 

/* 初始化接口.  */ 
static void  
el_init(xsc) 
void *xsc; 
{ 
struct el_softc *sc = xsc; 
struct ifnet *ifp; 
int s; 
u_short base; 

ifp = &sc->;arpcom.ac_if;/*定位ifnet结构*/ 
base = sc->;el_base;/*网卡基本I/O地址*/ 

/* 如果地址不知道,什么也不做. */ 
if(TAILQ_EMPTY(&ifp->;if_addrhead)) /* 在if.c中的if_attach例程 
中已经填充,由el_attach调用 
ether_attach时再调用if_attach */ 
return; 

s = splimp();/*关网络中断*/ 

/* 重设板卡. */ 
dprintf(("Resetting board...\n")); 
el_hardreset(sc);/*该函数在上面,重设硬件*/ 

/* 设置接收寄存器 rx */ 
dprintf(("Configuring rx...\n")); 
if(ifp->;if_flags & IFF_PROMISC)    /*是混杂模式?EL_RXC是0X6接收命令寄存器*/ 
outb(base+EL_RXC,(EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW)); 
else 
outb(base+EL_RXC,(EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW)); 
outb(base+EL_RBC,0);/*接收缓冲寄存器清0*/ 

/* 设置传输寄存器 TX */ 
dprintf(("Configuring tx...\n")); 
outb(base+EL_TXC,0); 

/* 开始接收 */ 
dprintf(("Starting reception...\n")); 
outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));/*EL_AC_IRQE是IRQ enable(可用) EL_AC_RX为接收寄存器*/ 

/* 设置一些开始使用的标志 */ 
ifp->;if_flags |= IFF_RUNNING;/*加上正在运行标志*/ 
ifp->;if_flags &= ~IFF_OACTIVE;/*去掉正在传输标志*/ 

/* 调用输出. */ 
el_start(ifp); 

splx(s);/*开网络中断*/ 
} 

/* 开始在接口上输出.从队列中得到包并输出他们,在输出中,留出接收用一 
部分时间,即打开中断再关闭中断,这样使接口接到的一些数据包不会丢失. 
  
 */ 
static void 
el_start(struct ifnet *ifp) 
{ 
struct el_softc *sc; 
u_short base; 
struct mbuf *m, *m0; 
int s, i, len, retries, done; 

/*  定位softc结构的指针*/ 
sc = ifp->;if_softc; 
base = sc->;el_base;/*基地址在输入输出指令时常要用到*/ 

dprintf(("el_start()...\n")); 
s = splimp();/*因为下面涉及到if_flags的操作,所以要关闭网络中断*/ 

/* 如果输出正在进行,则退出 */ 
if(sc->;arpcom.ac_if.if_flags & IFF_OACTIVE) 
return; 
sc->;arpcom.ac_if.if_flags |= IFF_OACTIVE;/*加上输出正在进行传输标志*/ 

/* 主循环 
 */ 
while(1) {/*唯一出口是准备传输的数据为空,即m0==NULL时*/ 
/* 从队列中移出下一数据包到m0中,请看头文件if_var.h 
#define IF_DEQUEUE(ifq, m) { \ 
(m) = (ifq)->;ifq_head; \           ifq是一mbuf指针队列,把第一个mbuf指针放到m中 
if (m) { \ 
if (((ifq)->;ifq_head = (m)->;m_nextpkt) == 0) \重排队列         
(ifq)->;ifq_tail = 0; \ 
(m)->;m_nextpkt = 0; \ 
(ifq)->;ifq_len--; \ 
} \ 
} 


*/ 
IF_DEQUEUE(&sc->;arpcom.ac_if.if_snd,m0);/*    &sc->;arpcom.ac_if.if_snd指向发送队列, 
该宏取出第一个mubf的指针放到m0中,看上面的说明. 
这是数据结构的好教材*/ 

/* 如果发送缓冲区指针为空,即已经发送完,则退出,此是该无穷循环的唯一出口. */ 
if(m0 == NULL) { 
sc->;arpcom.ac_if.if_flags &= ~IFF_OACTIVE;/*出去前当然要去掉输出正在进行标志*/ 
splx(s); 
return; 
} 

/* 关闭接收 */ 
outb(base+EL_AC,EL_AC_HOST);/*EL_AC_HOST为系统总线可访问缓冲,即系统总线网卡要用 */ 
outb(base+EL_RBC,0);/*接收缓冲寄存器清0*/ 

/* 拷贝mbuf中的数据到softc结构定义的成员el_pktbuf中,缓冲大小是EL_BUFSIZ即2048. */ 
len = 0; 
for(m = m0; m != NULL; m = m->;m_next) {   /* m0是一mbuf指针,也是一mbuf链的第一个,此 
次要发送的是一mbuf链,不是一单个mbuf*/ 
if(m->;m_len == 0) 
continue; 
bcopy(mtod(m,caddr_t),sc->;el_pktbuf+len,m->;m_len);/*m->;len是该mbuf链的数据长度, 
sc->;el_pktbuf是该卡的发送临时缓冲,要发 
送的数据在这集中,然后传送到网卡上,太费 
时间了,应该直接放置到网卡的存储器中.*/ 
len += m->;m_len; /*len是这次要发送的总数*/ 
} 
m_freem(m0);                                /*释放该mbuf链*/ 

len = max(len,ETHER_MIN_LEN);  /*ETHER_MIN_LEN是发送的最小长度*/ 

/* 如果有BPF,就交给BPF验证 */ 
if(sc->;arpcom.ac_if.if_bpf) 
bpf_tap(&sc->;arpcom.ac_if, sc->;el_pktbuf, len);/*你当然可以在这写一点自己的验证过程*/ 

/* 传送数据包到板卡 */ 
dprintf(("el: xfr pkt length=%d...\n",len)); 
i = EL_BUFSIZ - len;/*EL_BUFSIZ=2048字节*/ 
outb(base+EL_GPBL,(i & 0xff));       /*告诉发送的长度*/ 
outb(base+EL_GPBH,((i>;>;8)&0xff)); 
outsb(base+EL_BUF,sc->;el_pktbuf,len);/*传输数据到板卡*/ 

/* 开始发送数据包 */ 
retries=0;/*下面做循环用的,在发不出去时,循环15次*/ 
done=0;   /*done=1时发送成功了*/ 
while(!done) { 
if(el_xmit(sc,len)) { /* 调用发送例程,其实只要传送base就可以了 */ 
done = -1; 
break; 
} 
/* 检查输出后的状态,如果你要对watchdog支持,可以在这加上代码,即在5毫秒没发送出去,就调用el_watchdog() */ 
i = inb(base+EL_TXS); 
dprintf(("tx status=0x%x\n",i)); 
if(!(i & EL_TXS_READY)) {            /* 如果传输状态寄存器不是准备接受新帧就绪 */ 
dprintf(("el: err txs=%x\n",i));  /*那就是出错了*/ 
sc->;arpcom.ac_if.if_oerrors++; 
if(i & (EL_TXS_COLL|EL_TXS_COLL16)) {/*网络数据包碰撞*/ 
if((!(i & EL_TXC_DCOLL16)) && retries < 15) {/*做循环的目的是为了有错误时可重传15次*/ 
retries++; 
outb(base+EL_AC,EL_AC_HOST);/*EL_AC_HOST为系统总线可访问缓冲 */ 
} 
} 
else 
done = 1; 
} 
else { 
sc->;arpcom.ac_if.if_opackets++;/*统计用的,说明该卡成功发送一包*/ 
done = 1; 
} 
} 
if(done == -1)  /* 包没有传输(失败) */ 
continue; 

/* 现在给板卡一个机会接收.注意:在linux中曾经ALEN先生批评此卡好恐怖(他说要进博物馆,哈哈),并说在传输时 
会丢失进来的数据包,我查看了LINUX的驱动程序,确实是这样,但在FreeBSD中,给了一个机会,由此可证明他的 
关于"丢失包的说法不一定成立",但关于一个缓冲和一次只能发送一数据包的说法确实是真的,还有多播方面也 
不支持,我也希望大家最好不要去买这东西,和NE2000,PCI中的RTL8139芯片的网卡一样,性能太差了.*/ 
(void)inb(base+EL_AS);/*读辅助状态寄存器*/ 
outb(base+EL_AC,(EL_AC_IRQE|EL_AC_RX));/* 用IRQ(中断)使能和接收 写辅助命令寄存器*/ 
splx(s); 
/* 这有可能接收到中断(包到达) */ 
s = splimp(); 
} 
} 

/* 这是真正的传输包,由el_start()调用 
 */ 
static int 
el_xmit(struct el_softc *sc,int len) 
{ 
int gpl; 
int i; 

gpl = EL_BUFSIZ - len; 
dprintf(("el: xmit...")); 
outb((sc->;el_base)+EL_GPBL,(gpl & 0xff)); 
outb((sc->;el_base)+EL_GPBH,((gpl>;>;8)&0xff)); 
outb((sc->;el_base)+EL_AC,EL_AC_TXFRX);/*真正的传送指令*/ 
i = 20000; 
while((inb((sc->;el_base)+EL_AS) & EL_AS_TXBUSY) && (i>;0))/*如果传送还在忙,循环20000次等待*/ 
i--; 
if(i == 0) {/*这里有一个bug,大家发现没有,i到了0时也有可能传送成功,解决办法是把(i>;0)这条件放到前面*/ 
/*我稍微讲一下C,在编译C程序时,象while ( (a>;b) && (i>;0) )时,是这个样子 
top:if a>;b then 
if i>;0 then 
执行体 
endif 
endif 
goto top 
也就是说,当i=0时候,inb((sc->;el_base)+EL_AS)这指令还会执行,也有可能这时候传送完成了,而下面有给打出 
一个什么"tx not ready"的东东,而且返回失败,有得重新传送一次. 
*/ 
dprintf(("tx not ready\n")); 
sc->;arpcom.ac_if.if_oerrors++; 
return(-1); 
} 
dprintf(("%d cycles.\n",(20000-i))); 
return(0);/*成功*/ 
} 

/* 传递包到更高一级协议处理,即ether_input()例程.由elintr()调用 */ 
static __inline void 
elread(struct el_softc *sc,caddr_t buf,int len) 
{ 
register struct ether_header *eh; 
struct mbuf *m; 

eh = (struct ether_header *)buf;/*从buf中分出以太网头部*/ 

/* 
 * elget函数是把包放入一mbuf缓冲链中 
 */ 
m = elget(buf,len,&sc->;arpcom.ac_if); 
if(m == 0)/*出错了*/ 
return; 

ether_input(&sc->;arpcom.ac_if,eh,m);/*传输给上一层的包括ifnet结构,以太网头部,一mbuf*/ 
} 

/* 中断例程 */ 
static void 
elintr(int unit) 

⌨️ 快捷键说明

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