struct SNetIf DT_XDATA* NetIf,IP_ADDR DestIP) REENTRANT_SIG {
/* next host to receive the packet in rout */ DWORD NextIP;
// 以太网数据链路层首部结构体指针
struct SEtherHead DT_XDATA * pEtherHead; ETHERIF.C // 缓存控制块指针
struct SMemHead DT_XDATA *p;
// 缓存控制块中得到以太网数据链路层指针位置
// 入口时 MemHead 的.pStart 域指向 IP 数据报文位置 pEtherHead = (struct SEtherHead DT_XDATA *) (MemHead->pStart - sizeof(struct SEtherHead)); /* if DestIP in this subnet ... */ // ????????????????????????????
if ((NetIf->NetMask & NetIf->IPAddr) == (NetIf->NetMask & DestIP)) NextIP = DestIP; else
NextIP = NetIf->GateWay; /* find Ether addr of NextIP */
// 查找 NextIP 对应的网卡物理地址
if (ARPFind(pEtherHead->DestAddr,NextIP) == FALSE) {
/* send a arp query */
//---------------------------------------------------------------------
// 如果 ARP 高速缓存表中未找到 NextIP,则调用 ARPQuery 发送程序发送一条 // ARP 广播。其中在 ARPQuery 程序中已经填写好以太网数据链路层报文和 ARP // 报文。 ARPQuery 如果申请内存成功,则返回缓存控制块指针,否则返回 NULL。 //--------------------------------------------------------------------- if ((p = ARPQuery(NetIf,NextIP)) != NULL) { // 如果发送 ARP 广播时申请内存成功
// 调用网络接口设备队列的发送指针函数,发送 ARP 数据包 ((struct SEtherDevice DT_XDATA *)
(NetIf->Info))->send(p->pStart,sizeof(struct SARPPacket) + sizeof(struct SEtherHead));
MemFree(p); // 释放缓存控制块 } } else {
//---------------------------------------------------------------------
// 如果 ARP 高速缓存表中找到 NextIP,则 pEtherHead->DestAddr 中存储 // NextIP 对应的以太网物理地址。
//--------------------------------------------------------------------- /* fill ehter header, DestAddr already filled in ARPFind */
// 填写以太网数据链路层首部.ScrAddr 域=以太网源物理地址 // 网络接口设备队列指针中获取以太网源物理地址 MemCopy(pEtherHead->ScrAddr,
((struct SEtherDevice DT_XDATA *)(NetIf->Info))->Addr,ETHER_ADDR_LEN); // 填写以太网数据链路层首部.type 域=数据帧类型 // 以太网帧类型=IP 数据包 ETHERIF.C pEtherHead->type = htons(ETHER_TYPE_IP);
// 注:以太网目的物理地址已经在调用 ARPFind 程序时填写到 // pEtherHead->DestAddr 中。
/* send the packet. packet lenth is less than MemHead size */ // 调用网络接口设备队列的发送指针函数,发送 IP 数据包 return ((struct SEtherDevice DT_XDATA *)(NetIf->Info))->send(
pEtherHead,(WORD)(MemHead->pEnd - (BYTE DT_XDATA *)pEtherHead)); }
return FALSE;
/* free MemHead when it is acked in tcp model */ }
//===========================================================================
/* this function is called periodically.Get a packet from specific device. If there is a packet, call NetIf->Input to do more */ // 作 者:南开大学-李章林 // 注 释:李清林
// 日 期:2008 年3 月
// 声 明:英文注释由作者李章林添加,中文注释由■李清林添加。 // 转载时请保留上述信息。
// 成都理工学院/应用数字系/应用数字专业
//--------------------------------------------------------------------------- // 程序名称:EtherInput=以太网数据链路层接收子程序 // 入口参数:
// *NetIf=网络接口设备队列指针 // 出口参数: // 无
//=============================================================================
void EtherInput(struct SNetIf DT_XDATA * NetIf) REENTRANT_SIG {
struct SMemHead DT_XDATA *MemHead; // 缓存控制块指针
struct SEtherHead DT_XDATA *pEtherHead; // 以太网数据链路层指针 struct SMemHead DT_XDATA *p; // 临时缓存控制块指针
/* if there is a packet to deal with */
// 如果以太网网络接口设备接收到数据包
while ((MemHead = ((struct SEtherDevice DT_XDATA *)(NetIf->Info))->recv()) != NULL) {
/* Note, pStart point to EtherHead */
// 以太网数据链路层指针 EetherHead 指向数据包数据链路层位置 pEtherHead = (struct SEtherHead DT_XDATA *)(MemHead->pStart); /* which packet type */
switch(ntohs(pEtherHead->type)) // 分析数据包帧类型 ETHERIF.C {
case ETHER_TYPE_IP: // IP 数据包
/* before pass to IP layer, let MemHead->pStart point to IP header */
MemHead->pStart += sizeof(struct SEtherHead); /* pass to IP layer for more dealing */
// 将缓存控制块指针的 pStart 域指针指向IP 首部
IPInput(MemHead); // 调用 IP 数据包接收子程序, break;
case ETHER_TYPE_ARP: // ARP 数据包
//--------------------------------------------------------------------------
// ARPInput 程序中如果接收到 ARP 请求报文,填写以太网数据链路层首部信息,然后 // 填写 ARP 应答报文,并返回 MemHead;如果接收到 ARP 应答报文,填写 ARP 高速缓存表,
// 然后返回 NULL。据此通过返回值可确定是接收到 ARP 请求报文还是 ARP 应答报文。 //-------------------------------------------------------------------------- if ((p = ARPInput(MemHead,NetIf)) != NULL) {
/* a arp reply need to be send */
// 接收到 ARP 请求报文后,发送 ARP 应答报文
// 调用网络接口设备发送函数指针发送 ARP 应答报文 ((struct SEtherDevice DT_XDATA *)(NetIf->Info))->send( p->pStart,sizeof(struct SARPPacket) + sizeof(struct SEtherHead)); MemFree(p); }
/* 'MemHead' is freed in ARPInput() */ break;
//---------------------------------------------------------------------------
// 以太网数据链路层支持三种数据包。而一般嵌入式 TCP/IP 协议栈只支持IP 数据包和 // ARP 数据包,不支持 RARP 数据包(RARP 数据包针对无盘网络工作)。 //--------------------------------------------------------------------------- default:
/* unknown packet type free */ MemFree(MemHead);
} } }
//=============================================================================
/* ethernet device init */
// 作 者:南开大学-李章林 // 注 释:李清林
// 日 期:2008 年3 月
// 声 明:英文注释由作者李章林添加,中文注释由■李清林添加。 // 转载时请保留上述信息。 ETHERIF.C // 成都理工学院/应用数字系/应用数字专业
//---------------------------------------------------------------------------
// 程序名称:EtherDevInit=以太网数据链路层网络接口设备队列初始化子程序 // 入口参数:
// *pDevice=以太网数据链路层设备指针 // EtherAddr[]=网卡物理地址
// 以太网数据链路层发送指针函数
// BOOL (DT_CODE * send)(void DT_XDATA *buf, WORD size) // 以太网数据链路层接收指针函数
// struct SMemHead DT_XDATA *(DT_CODE * recv)() // 出口参数: // 无
//=============================================================================
void EtherDevInit(struct SEtherDevice DT_XDATA * pDevice, BYTE EtherAddr[],
BOOL (DT_CODE * send)(void DT_XDATA *buf, WORD size) REENTRANT_SIG,
struct SMemHead DT_XDATA *(DT_CODE * recv)() REENTRANT_SIG) REENTRANT_MUL {
// 网卡物理地址拷贝到以太网数据链路层设备驱动结构体指针.Addr 域 MemCopy(pDevice->Addr,EtherAddr,ETHER_ADDR_LEN); // 填写以太网数据链路层设备驱动结构体指针.recv 域 pDevice->recv = recv;
// 填写以太网数据链路层设备驱动结构体指针.send 域 pDevice->send = send; }