?? pingtest.c
字號(hào):
/*****************************************************************************\
* *
* 以太網(wǎng)控制器測試模塊 *
* *
* 該模塊實(shí)現(xiàn)了基于以太網(wǎng)的ARP回應(yīng)和ICMP回應(yīng) *
* *
\*****************************************************************************/
#include "PingTest.h"
#include "Ethernet.h"
// 本地IP地址
// TODO: 可根據(jù)需要改為其它地址
IP_ADDR g_LocalIPAddr = 192u << 24 | 168u << 16 | 196u << 8 | 200u;
// 以太網(wǎng)協(xié)議頭
typedef struct eth_hdr {
u16 padding;
ETH_ADDR dest, src;
u16 type;
} ETH_HDR;
#define ETHTYPE_ARP 0x0806
#define ETHTYPE_IP 0x0800
// ARP協(xié)議頭
typedef struct arp_hdr {
u16 hwtype;
u16 proto;
u16 _hwlen_protolen;
u16 opcode;
ETH_ADDR shwaddr;
u16 sip_h, sip_l;
ETH_ADDR dhwaddr;
u16 dip_h, dip_l;
} ARP_HDR;
#define ARP_REQUEST 1
#define ARP_REPLY 2
// IP協(xié)議頭
typedef struct ip_hdr {
u16 _v_hl_tos; // version / header length / type of service
u16 len; // total length
u16 id; // identification
u16 offset; // fragment offset field
#define IP_RF 0x8000 // reserved fragment flag
#define IP_DF 0x4000 // dont fragment flag
#define IP_MF 0x2000 // more fragments flag
#define IP_OFFMASK 0x1fff // mask for fragmenting bits
u8 ttl, proto; // time to live / protocol
u16 chksum; // checksum
IP_ADDR src, dest; // source and destination IP addresses
} IP_HDR;
#define IPH_V(hdr) (ntohs((hdr)->_v_hl_tos) >> 12)
#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 6) & 0x3c)
#define IP_PROTO_ICMP 1
// ICMP協(xié)議頭
typedef struct icmp_hdr {
u8 type, code;
u16 chksum;
u16 id;
u16 seqno;
} ICMP_HDR;
#define ICMP_ER 0
#define ICMP_ECHO 8
// 交換字節(jié)順序(雙字節(jié))
__inline u16 bswap16(u16 x)
{
return x << 8 | x >> 8;
}
// 交換字節(jié)順序(四字節(jié))
__inline u32 bswap32(u32 x)
{
return x << 24 | x << 8 & 0x00ff0000
| x >> 8 & 0x0000ff00 | x >> 24;
}
#define htons bswap16
#define htonl bswap32
#define ntohs htons
#define ntohl htonl
// 計(jì)算校驗(yàn)和
static u32 inet_chksum(void *dataptr, int len)
{
u32 acc;
for(acc = 0; len > 1; len -= 2)
{
acc += *(u16 *)dataptr;
dataptr = (u16 *)dataptr + 1;
}
if(len)
acc += htons((*(u8 *)dataptr) << 8);
while(acc >> 16)
acc = (acc & 0xffff) + (acc >> 16);
return acc ^ 0xffff;
}
// 回應(yīng)IP包
static void ip_reply(IP_HDR *iphdr, int len)
{
ETH_HDR *ethhdr = (ETH_HDR *)iphdr - 1;
int i;
iphdr->dest = iphdr->src;
iphdr->src = htonl(g_LocalIPAddr);
iphdr->len = htons(len);
iphdr->id = 0;
iphdr->offset = htons(IP_DF);
iphdr->chksum = 0;
iphdr->chksum = inet_chksum(iphdr, sizeof(IP_HDR));
for(i = 0; i < 3; i++)
{
ethhdr->dest[i] = ethhdr->src[i];
ethhdr->src[i] = local_eth_addr[i];
}
NIC_SendPack((u16 *)ethhdr + 1, len + (sizeof(ETH_HDR) - 2));
}
// 處理ICMP輸入
static void icmp_input(IP_HDR *iphdr, int len)
{
ICMP_HDR *icmphdr;
if(len < sizeof(IP_HDR) + sizeof(ICMP_HDR))
return;
icmphdr = (ICMP_HDR *)(iphdr + 1);
if(icmphdr->type != ICMP_ECHO)
return;
if(inet_chksum(icmphdr, len - sizeof(IP_HDR)))
return;
icmphdr->type = ICMP_ER;
if(icmphdr->chksum >= htons(0xffff - (ICMP_ECHO << 8)))
icmphdr->chksum += htons(ICMP_ECHO << 8) + 1;
else
icmphdr->chksum += htons(ICMP_ECHO << 8);
ip_reply(iphdr, len);
}
// 處理IP輸入
static void ip_input(IP_HDR *iphdr, int len)
{
if(IPH_V(iphdr) != 4)
return;
if(IPH_HL(iphdr) != sizeof(IP_HDR))
return;
if(inet_chksum(iphdr, sizeof(IP_HDR)))
return;
if(iphdr->offset & htons(IP_OFFMASK | IP_MF))
return;
switch(iphdr->proto)
{
case IP_PROTO_ICMP:
icmp_input(iphdr, len);
break;
}
}
// 處理ARP輸入
static void arp_input(ETH_HDR *ethhdr, int len)
{
int i;
ARP_HDR *arphdr;
if(len < sizeof(ETH_HDR) + sizeof(ARP_HDR))
return;
arphdr = (ARP_HDR *)(ethhdr + 1);
if((ntohs(arphdr->dip_h) << 16 | ntohs(arphdr->dip_l)) != g_LocalIPAddr)
return;
switch(ntohs(arphdr->opcode))
{
case ARP_REQUEST:
arphdr->opcode = htons(ARP_REPLY);
arphdr->dip_h = arphdr->sip_h;
arphdr->dip_l = arphdr->sip_l;
arphdr->sip_h = htons(g_LocalIPAddr >> 16);
arphdr->sip_l = htons(g_LocalIPAddr & 0xffff);
for(i = 0; i < 3; i++)
{
ethhdr->dest[i] = arphdr->dhwaddr[i] = arphdr->shwaddr[i];
ethhdr->src[i] = arphdr->shwaddr[i] = local_eth_addr[i];
}
NIC_SendPack((u16 *)ethhdr + 1, len - 2);
break;
}
}
// 處理以太網(wǎng)輸入
static void eth_input(ETH_HDR *ethhdr, int len)
{
switch(htons(ethhdr->type))
{
case ETHTYPE_ARP:
arp_input(ethhdr, len);
break;
case ETHTYPE_IP:
ip_input((IP_HDR *)(ethhdr + 1), len - sizeof(ETH_HDR));
break;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// 功能:
// 以太網(wǎng)測試入口函數(shù)
// 參數(shù):
// buf 以太網(wǎng)數(shù)據(jù)包地址,必須按4字節(jié)對(duì)齊,必須在開頭包含2字節(jié)填充
// len 數(shù)據(jù)包長度(包括2字節(jié)填充)
// 返回值:
// 無
//
void PingTest_Input(void *buf, int len)
{
eth_input((ETH_HDR *)buf, len);
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -