📄 ip.c
字号:
#include "ip.h"
#include "tcp.h"
#include "ARP.h"
#include "UDP.h"
#include "ICMP.h"
#include "rtl8019.h"
xdata ST_IP_HEAD_FORMAT gstIphead;
xdata UWORK8 IPLocalAddress_buf[IP_LEN]; // 本地IP地址
xdata UWORK8 SubNetMask_buf[IP_LEN]; // 子网掩码
xdata UWORK8 GateWay_buf[IP_LEN]; // 网关
xdata UWORK8 IPSourceddress_buf[IP_LEN]; // IP地址
xdata UWORK8 IPDestAddress_buf[IP_LEN]; /* 目标IP地址 */
UWORK16 SourcePort; //源端口号
UWORK16 DesPort; //目标端口号
/*********************************************************************
函数名: void IpSend(void)
功能: Ip发送数据
输入: 发送数据的长度
输出: 将数据打包成IP包
返回: None
日期: 2004/12/28
*********************************************************************/
void IpSend(void)
{
ST_IP_HEAD_FORMAT *pIpHeadBuff;
MAC_Remote_buf[12] = 0x08; // IP协议
MAC_Remote_buf[13] = 0x00;
pIpHeadBuff = (ST_IP_HEAD_FORMAT *)&NetSend_buf[0]; // IP头
memcpy(&NetSend_buf[0],&gstIphead,20);
pIpHeadBuff->usCheckSum = 0;
pIpHeadBuff->usCheckSum = CheckSum((UWORK16 *)&NetSend_buf[0],20); // 计算IP头校验和
//SerialSendbuf((UWORK8 *)&NetSend_buf[0],gstIphead.usTotalLen); //读取IP总的数据长度
SendEthernetPacket(pIpHeadBuff->usTotalLen);
}
/*********************************************************************
函数名: void IpOrRouter(void)
功能: IP路由选择
输入: 初始化或者改变IP的时候
输出: 判断IP还是路由
返回: None
日期: 2005/01/24
更新: 2006/05/21
*********************************************************************/
void IpOrRouter(void)
{
UWORK32 ulLocalIP,ulRemoteIP,ulMask;
UWORK8 ucaTemp[4],ucLoop;
memcpy((UWORK8 *)&ulLocalIP,&IPLocalAddress_buf[0],IP_LEN);
memcpy((UWORK8 *)&ulMask,&SubNetMask_buf[0],IP_LEN);
for(ucLoop = 0; ucLoop < REMOTE_IP_NUM; ucLoop++) // 目的IP地址 /
{
memset(&ucaTemp[0],0,4);
if(0 == memcmp(&ucaTemp[0],&ArpCache_Buf[ucLoop].ucaIP[0],IP_LEN))
{
ArpCache_Buf[ucLoop].ucIPValible = 0; // 没有合法的IP,规定0.0.0.0为非法IP
}
else
{
ArpCache_Buf[ucLoop].ucIPValible = 1;
memcpy((UWORK8 *)&ulRemoteIP,&ArpCache_Buf[ucLoop].ucaIP[0],IP_LEN);
if((ulLocalIP & ulMask) == (ulRemoteIP & ulMask))
{
ArpCache_Buf[ucLoop].ucIpOrRouter = 0; // 网络号相同,直接交付
memcpy(&ArpCache_Buf[ucLoop].ucaArpIp[0],&ArpCache_Buf[ucLoop].ucaIP[0],IP_LEN);
}
else
{
ArpCache_Buf[ucLoop].ucIpOrRouter = 1; // 网络号不相同,使用路由间接交付
memcpy(&ArpCache_Buf[ucLoop].ucaArpIp[0],&GateWay_buf[0],IP_LEN);
}
}
ArpCache_Buf[ucLoop].ucStatus = 'f';
}
}
/*********************************************************************
函数名: void IpReceive(void)
功能: Ip处理,因为是接收一帧处理一帧,不用返回成功失败
输入: 接收的帧是Ip帧
输出: 处理IP分组
返回: None
日期: 2004/12/20
*********************************************************************/
void IpReceive(void)
{
ST_IP_HEAD_FORMAT *pIpHead;
ST_UDP_HEAD_FORMAT *pUdpHead;
UWORK16 usFragmentOffset;
pIpHead = (ST_IP_HEAD_FORMAT *)&gstaRevEthernet.ucaPacket[0]; // 指向IP头
pUdpHead = (ST_UDP_HEAD_FORMAT *)&gstaRevEthernet.ucaPacket[20];
// IP数据需满足3个条件 1.广播包 2.本地IP地址
// 只处理IPV4和基本长度的IP包
if(0x45 == pIpHead->ucVerAndLen)
{
if(0x0000 == CheckSum((UWORK16 *)&gstaRevEthernet.ucaPacket[0],20)) // 计算IP校验头
{
if(0 == (pIpHead->usSegOffset & 0x3fff)) // 没有分片的处理,直接从接收缓冲拷贝数据
{
if(pIpHead->usTotalLen > 1514) // 不能超过以太网的最大包长度,防止恶意攻击
{
return;
}
gbHaveFragment = FALSE; // 清分片标志
switch(pIpHead->ucprotocol)
{
case ICMP: //网间网控制报文协议,PING命令
IcmpReceive(pIpHead->usTotalLen - 20);
break;
case UDP:
UdpReceive();
break;
case TCP: //TCP协议
TCPReceive();
break;
case IGMP: //IGMP协议
// IGMPReceive();
break;
default:
break;
}
}
else // 建立一个缓冲,用于组装分散包
{
usFragmentOffset = (pIpHead->usSegOffset & 0x1fff) * 8;
if(pIpHead->usSegOffset & MORE_FRAGMENT) // 有更多的分片
{
if( 0 == usFragmentOffset) // 第一个分片
{
memcpy(&NetSend_buf[0],&gstaRevEthernet.ucaPacket[0],20); // ICMP需要
memcpy(&gucaSegTemp[0],&gstaRevEthernet.ucaPacket[0],pIpHead->usTotalLen);
RevIpID = pIpHead->usID;
gbHaveFragment = TRUE;
}
else //中间分片
{
if(RevIpID != pIpHead->usID) // 是否为同一个ID /
{
return;
}
if((usFragmentOffset + pIpHead->usTotalLen) <= SEGMENT_DATA) // 只有5K的缓存
{
memcpy(&gucaSegTemp[usFragmentOffset + 20],&gstaRevEthernet.ucaPacket[20],pIpHead->usTotalLen - 20);
}
}
}
else // 最后一个分片
{
if(RevIpID != pIpHead->usID) // 是否为同一个ID
{
return;
}
if((usFragmentOffset + pIpHead->usTotalLen) <= SEGMENT_DATA) // 只有5K的缓存
{
memcpy(&gucaSegTemp[usFragmentOffset + 20],&gstaRevEthernet.ucaPacket[20],pIpHead->usTotalLen - 20);
// 还需要判断数据是否完全到齐?????
switch(NetSend_buf[9])
{
case ICMP:
IcmpReceive(usFragmentOffset + pIpHead->usTotalLen - 20);
break;
case UDP:
UdpReceive();
break;
case TCP: //TCP协议
TCPReceive();
break;
case IGMP: //IGMP协议
// IGMPReceive();
break;
default:
break;
}
}
}
}
}
}
}
/*********************************************************************
函数名: UWORK16 CheckSum(UWORK16 *pusPointer,UWORK16 usDataLen)
功能: 计算校验和
输入: 十六位的数据指针,数据长度
输出: 计算校验和
返回: 校验和的反码
日期: 2004/12/20
*********************************************************************/
UWORK16 CheckSum(UWORK16 *pusPointer,UWORK16 usDataLen)
{
UWORK8 ucDataLen,ucNum,ucLoop,ucLoopNum;
UWORK16 usRealDataLen;
UWORK32 ulCheckSum = 0;
usRealDataLen = usDataLen >> 1; // 8位长度变为16位长度
ucNum = usRealDataLen / 255;
ucDataLen = usRealDataLen % 255;
for(ucLoopNum = 0; ucLoopNum < ucNum; ucLoopNum++) // 将循环变量换成8位,提高运行速度
{
for(ucLoop = 0; ucLoop < 255; ucLoop++)
{
ulCheckSum += *pusPointer;
pusPointer++;
}
}
for(ucLoop = 0; ucLoop < ucDataLen; ucLoop++) // 计算剩余的数据
{
ulCheckSum += *pusPointer;
pusPointer++;
}
// 数据是单数还要将最后一个数据加上,低8位补零
if(usDataLen & 0x0001)
{
ulCheckSum += (*pusPointer & 0xff00);
}
ulCheckSum = (ulCheckSum >> 16) + (ulCheckSum & 0x0000ffff); // 加上进位部分
ulCheckSum += (ulCheckSum >> 16); // 可能再次进位,再加上进位部分,之后不可能再进位
usRealDataLen = (UWORK16)ulCheckSum;
usRealDataLen = (~usRealDataLen);
return usRealDataLen;
}
/*********************************************************************
函数名: void RcvEthernetData(void)
功能: 接收以太网数据
输入: None
输出: None
返回: OK, ERROR
日期: 2007/03/13
*********************************************************************/
void RcvEthernetData(void)
{
UWORK16 ucTemp,ucResult;
EX0 = FALSE; // 禁止外部中断0
if(0 != RTL8019asRcvNum) // 以太网芯片缓存中是否有以太网包
{
EX0 = FALSE; // 禁止外部中断0
ucTemp = RevEthernetPacket(); //解析网络包
// SerialSendbuf((UWORK8 *)&gstaRevEthernet.usprotocol,sizeof(ST_RECEIVE_ETHERNET));
EX0 = TRUE; // 外部中断0使能
if(OK == ucTemp) // 正确接收了数据,记录的缓存减1
{
RTL8019asRcvNum--;
EthernetNoDataFlag = FALSE;
switch(gstaRevEthernet.usprotocol) // 劈以太网帧
{
case IP_type: //IP协议
IpReceive();
break;
case ARP_type: //ARP协议
ArpProcess();
break;
default:
break;
}
}
}
else // 可能中断未被及时执行
{
if(FALSE == EthernetNoDataFlag) // 可能有没有及时中断造成数据没有读完
{
EX0 = FALSE; // 禁止外部中断0
Page1();
RTL8019asRead(RW1_CURR,ucTemp); // 比较读指针和写指针,判断是否有数据
Page0();
if((ucTemp < 0x80) && (ucTemp > 0x4b)) // 读的过程是否出错,CUUR处于0x4c~0x7f
{
RTL8019asRead(RW0_BNRY,ucResult);
ucResult++;
if(ucResult > 0x7f)
{
ucResult = 0x4c;
}
if(ucTemp != ucResult) // 是否有没有读完的数据
{
ucTemp = RevEthernetPacket();
EX0 = TRUE; // 外部中断0使能
if(OK == ucTemp) // 正确接收了数据,记录的缓存减1
{
switch(gstaRevEthernet.usprotocol) // 劈以太网帧
{
case IP_type:
IpReceive();
break;
case ARP_type:
ArpProcess();
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -