📄 ip.c
字号:
#include "test.h"
#include "def.h"
#include "ip.h"
////////////////////////////////////////
int WantNext = 0;
#define DEBUGSTRING(str) //printf("at %d:%s\r\n",__LINE__,str)
#define CONFIRMTONE
U8 nettest; //定义网络测试0x80,冲突检测0xa0,主机查询0x90
//位7表示网络测试中,在查询IP冲突和主机时需要置位
//位6用于发送一个包
//位5表示查询主机IP
//低4位表示测试的次数
U8 nettestaddr; //网络测试的低位地址
struct nicipAddr myIP,remoteIP,hostIP;
unsigned int localIP = IP_ADDR(192,168,1,100); //IP_ADDR(192,168,0,100);
typedef struct
{
unsigned int ip;
char mac[6];
}arp_tbl;
#define MAX_ARP_COUNT 6
int gi_arppos = 0;
arp_tbl gstr_arptbl[MAX_ARP_COUNT];
void AddArpTbl(unsigned int ip,void* mac)
{
if( FindArp(ip,0) )
return;
gstr_arptbl[gi_arppos].ip = ip;
memcpy(gstr_arptbl[gi_arppos].mac,mac,6);
gi_arppos++;
gi_arppos %= MAX_ARP_COUNT;
}
int FindArp(unsigned int ip,void* mac)
{
int i;
for( i = 0; i < MAX_ARP_COUNT; i++)
{
if( ip == gstr_arptbl[i].ip )
{
if( mac )
memcpy(mac,gstr_arptbl[i].mac,6);
return 1;
}
}
return 0;
}
extern U16 invert16(U16 w)
{
UNION16 dt1,dt2;
dt1.i = w;
dt2.b[0] = dt1.b[1];
dt2.b[1] = dt1.b[0];
return(dt2.i);
}
extern int net_send_packet(char* data,int len);
int NicSendTxFrame(U16 ProtocolType,void *buffer,U16 length)
{
STR_ETHHEAD* ehead = (STR_ETHHEAD*)buf;
//数据包的最小长度等于64字节
if (length < 46)
{
length = 46;
}
memcpy(ehead->DestMac,remoteIP.Mac,6);
memcpy(ehead->SrcMac,myIP.Mac,6);
ehead->Type = ProtocolType;
memcpy(ehead->buffer,buffer,length);
return net_send_packet((char*)ehead,12+2+length);
}
void net_open(void);
char mac_addr[] = {0x00,0x11,0x22,0x33,0x44,0x55};
void InitIP(void)
{
net_open();
//设置本机的IP地址
myIP.Ip.l = localIP;
//设置本机的MAC地址
memcpy(myIP.Mac,mac_addr,6);
set_mac_address(myIP.Mac);
get_mac_address(myIP.Mac);
}
void ReceivedEther(char *buffer,int length)
{
unsigned short ProtocolType;
ProtocolType = buffer[12] | (buffer[13]<<8);
memcpy(remoteIP.Mac,buffer+6,6);
memcpy(buffer,buffer+14,length-14);
ReceivedIP(buffer,ProtocolType);
}
extern int IsALLSrc(U8 * dest,U8 src,U16 len)
{
for( ; len ; len--)
{
if((*dest) != src)
{
return(FALSE);
}
dest++;
}
return(TRUE);
}
////////////////////////////////////////
#define headLen 20
//声明使用的外部函数
//内部使用的函数预定义
extern int SendTxFrame(U16 ProtocolType,void *buffer,U16 length);
extern void ArpFun(STR_ARP *arp);
extern void SendArp(STR_ARP *arp,U16 op);
extern void IpFun(STR_IP *ip);
extern void UdpFun(STR_UDP *udp);
extern void IcmpFun(STR_ICMP *icmp,U16 icmplen);
extern int UdpSend(STR_UDP *udp,U16 length);
//定义模块变量
U8 const arpHead[] = {0x00,0x01,0x08,0x00,0x06,0x04,0x00};
U8 const rarpHead[]= {0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x03};
String * PrintIp(void* str,char* ipa)
{
sprintf((char*)str,"%u.%u.%u.%u",ipa[0],ipa[1],ipa[2],ipa[3]);
return str;
}
String * PrintMac(void* str,char* mac)
{
sprintf((char*)str,"%02x:%02x:%02x:%02x:%02x:%02x",
mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
return str;
}
// 检查是否内网通讯,
// 内网通讯设置通讯IP为内网IP
// 外网通讯设置通讯IP为外网IP
static void CheckLocalNetWork(void)
{
myIP.Ip.l = localIP;
FindArp(remoteIP.Ip.l,remoteIP.Mac);
if ( IsALLSrc(remoteIP.Mac,0x00,6) )
{
LookupMac(remoteIP.Ip.b[3]);
}
}
/*
函数 TCP/IP的校验和计算方法
输入 buf 要计算的校验和缓冲区首地址
length 缓冲区大小
*/
U16 GenCheckSum(U8 *buf,U16 length)
{
U32 checksum;
checksum = 0;
while(length > 0)
{
checksum += *buf*0x100;
buf++;
length--;
if ( length > 0 )
{
checksum += *buf++;
length--;
}
}
while(checksum >> 16)
{
checksum = (checksum & 0xffff) + (checksum >> 16);
}
#ifdef LITTLE_ENDIAN
checksum = (~checksum & 0xffff);
return(ENDIAN16(checksum));
#endif
#ifdef BIG_ENDIAN
return (~checksum);
#endif
}
/*
函数 处理来自NIC层以及其它底层的数据包
数据格式如下
*/
void ReceivedIP(void *buffer,U16 ProtocolType)
{
//判断数据包的类型域
switch(ProtocolType)
{
case P_ARP: //接收到ARP的数据包
DEBUGSTRING("arp");
ArpFun(buffer);
break;
case P_RARP: //接收到RARP的数据包
DEBUGSTRING("rarp");
#ifdef NET_RARP
RarpFun(buffer);
#endif
break;
case P_IP: //接收到IP数据包
DEBUGSTRING("ip");
IpFun(buffer);
break;
default:
//DEBUGSTRING("default");
break;
}
}
void ArpChangeEndian(STR_ARP *arp)
{
#ifdef LITTLE_ENDIAN
arp->Op = ENDIAN16(arp->Op);
#endif
}
/*
功能 ARP功能函数,主要用于查询和回答相应的MAC地址
硬件类型(16) 协议类型(16)
硬件长度(8) 协议长度(8) 操作(16)
发送站硬件地址
发送站协议地址
目标站硬件地址
目标站协议地址
*/
void ArpFun(STR_ARP *arp)
{
U32 SrcAddr,DestAddr;
SetLocalIp();
#ifdef LITTLE_ENDIAN
ArpChangeEndian(arp);
#endif
memmove(&SrcAddr,arp->SrcProtocolAddr,4);
memmove(&DestAddr,arp->DestProtocolAddr,4);
switch (arp->Op)
{
case 1: //ARP请求操作,这里发送请求应答
DEBUGSTRING("arp request");
#ifdef DEBUGMODE
printf("\r\nmyIP:%08x DestIP:%08x ",myIP.Ip.l,DestAddr);
#endif
if (myIP.Ip.l == DestAddr)
{
remoteIP.Ip.l = SrcAddr; //记录远端的IP
//在这里添加路由信息
AddArpTbl(remoteIP.Ip.l,remoteIP.Mac);
SendArp(arp,2); //应答IP数据包
}
break;
case 2: //ARP应答操作
DEBUGSTRING("arp ack");
if(myIP.Ip.l == DestAddr)
{
if (nettest & 0x80)
{
CONFIRMTONE;
nettest = 0;
}
nettestaddr = 0;
//找到远端的IP地址
remoteIP.Ip.l = SrcAddr;
//在这里添加路由信息
AddArpTbl(remoteIP.Ip.l,remoteIP.Mac);
}
break;
default:
DEBUGSTRING("default");
break;
}
}
//功能 ARP数据包的发送函数
//输入 op ARP的操作码
//输出
//返回
void SendArp(STR_ARP *arp,U16 op)
{
//网络媒体是以太网
//填充NIC的头部信息(含包类型)
memmove(arp,arpHead,sizeof(arpHead));
//填充操作码
arp->Op = op;
//填充发送站硬件地址
//填充发送站IP地址
memmove(arp->SrcHardAddr,&myIP.Mac,6);
memmove(arp->SrcProtocolAddr,&myIP.Ip,4);
//填充目标站硬件地址
//填充目标站IP地址
memmove(arp->DestHardAddr,&remoteIP.Mac,6);
memmove(arp->DestProtocolAddr,&remoteIP.Ip,4);
ArpChangeEndian(arp);
SendTxFrame(P_ARP,(void*)arp,42); //ARP的数据长度是42个字节
}
/*
功能 查找对应IP地址的MAC地址
*/
void LookupMac(U8 addr)
{
STR_ARP arp;
remoteIP.Ip.l = (myIP.Ip.l & 0x00ffffff) | (addr << 24);
memset(remoteIP.Mac,0xff,6);
SendArp(&arp,1);
}
#ifdef NET_RARP
void RarpFun(void)
{
if (arp.oph != 0)
{
//RARP的高位操作码非法
return;
}
if (arp.oph != 4)
{
//不支持的操作
return;
}
//设置本机的IP地址
// myIP.ip = *(U32 *)&nicRxBuffer[14+8+6];
}
void SendRarp(U8 op)
{
//网络媒体是以太网
if (op != 3)
{
return;
}
//发送广播数据包
memset(remoteIP.Mac,0xff,6);
// memcpy(&nicTxBuffer[12],rarpHead,10);
//发送站的硬件地址
// memcpy(&nicTxBuffer[22],&myIP.mac,6);
//发送站IP地址,目标MAC和IP地址未知,不需要填充
// memset(&nicTxBuffer[28],0x00,14);
SendTxFrame(42);
}
#endif
void IpChangeEndian(STR_IP *ip)
{
#ifdef LITTLE_ENDIAN
ip->Len = ENDIAN16(ip->Len);
ip->Id = ENDIAN16(ip->Id);
ip->Flag = ENDIAN16(ip->Flag);
#endif
}
/*
函数 IP数据包的处理程序
处理的数据包包含UDP,ICMP
*/
void IpFun(STR_IP *ip)
{
//判断校验和是否正确
if(GenCheckSum((U8 *)ip,headLen) != 0x0000)
{
//校验和错误
DEBUGSTRING("checksum error");
#ifdef DEBUGMODE
printf("\r\nchecksum: 0x%04x",GenCheckSum((U8 *)ip,headLen));
#endif
return;
}
IpChangeEndian(ip);
// DEBUGSTRING("IpFun");
// Tell2(ip->DestIp,localIP);
if(ip->DestIp == localIP)
{// 使用本地以太网端口
SetLocalIp();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -