uip移植到window平台目的是为仿真单片机运行环境,方便调试和学习,加快开发。
一、准备工作
下载uip 1.0 https://github.com/adamdunkels/uip/tags
下载wpcap sdk
下载wireshark
二、uip协议栈移植
使用vs2008创建控制台工程,解压uip代码。复制unix文件夹,重命名为win。
2.1、修改clock-arc.c
clock_time_t
clock_time(void)
{
return GetTickCount();
}
以上函数是获取系统运行时间,单位为ms。
2.2、修改tapdev.c
//网卡初始化
void tapdev_init(void)
{
EthernetInit();
}
//读取网络数据
unsigned int tapdev_read(void)
{
return EthernetRead(uip_buf,UIP_BUFSIZE);
}
//发送网络数据
void tapdev_send(void)
{
EthernetSend(uip_buf,uip_len);
}
2.3、增加intetypes.h
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
#define IP2DWORD(a,b,c,d) ((uint32_t)(uint8_t)(d)|(uint32_t)(uint8_t)(c)<<8|(uint32_t)(uint8_t)(b)<<16|(uint32_t)(uint8_t)(a)<<24)
#define DWORD2IP(val,array) \
do { \
array[0] = (uint8_t)((val >> 24) & 0x000000FF); \
array[1] = (uint8_t)((val >> 16) & 0x000000FF); \
array[2] = (uint8_t)((val >> 8) & 0x000000FF); \
array[3] = (uint8_t)((val >> 0) & 0x000000FF); \
} while(0)
#define ENDIANCHANGE32(A) ((((uint32_t)(A) & 0xff000000) >> 24) | \
(((uint32_t)(A) & 0x00ff0000) >> 8) | \
(((uint32_t)(A) & 0x0000ff00) << 8) | \
(((uint32_t)(A) & 0x000000ff) << 24))
#define snprintf _snprintf
2.4、配置uip-conf.h
#define UIP_CONF_BUFFER_SIZE 640 //wifi环境下DHCP包大于420
#define UIP_UDP_APPCALL uip_udp_appcall
typedef struct httpd_state uip_tcp_appstate_t;
typedef struct httpd_state uip_udp_appstate_t;
至此已移植完成。
三、收发网络数据包
使用uip协议栈后,要直接收发以太网包。这时要用到winpcap。
int EthernetInit()
{
if (pcap_findalldevs(&alldevs, errbuf) == -1)
{
return -2;
}
} if ((fp = pcap_open_live(alldevs->name,
65536, // portion of the packet to capture. It doesn't matter in this case
1, // promiscuous mode (nonzero means promiscuous)
1000,
errbuf // error buffer
)) == NULL)
{
DisplayErrorMsg(errbuf);
pcap_freealldevs(alldevs);
alldevs = NULL;
return -1;
}
int EthernetSend(void* buffer,int nSize)
{
if(fp == NULL) return -1;
if (pcap_sendpacket(fp,(const u_char*)buffer,nSize) != 0)
{
pcap_geterr(fp);
return 0;
}
return 1;
}
int EthernetRead(char* buffer,int nSize)
{
if(fp == NULL) return -1;
pcap_loop(fp, 1, packet_handler, NULL);
}
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
memcpy(szCapBuffer,pkt_data,bufferLen);
}
四、测试
void uIP_Net_Init(void)
{
timer_set(&periodic_timer, CLOCK_SECOND / 2);
timer_set(&arp_timer, CLOCK_SECOND * 10);
uip_ethaddr.addr[0] = 0x00;
uip_ethaddr.addr[1] = 0x1B;
uip_ethaddr.addr[2] = 0x11;
uip_ethaddr.addr[3] = 0x13;
uip_ethaddr.addr[4] = 0x86;
uip_ethaddr.addr[5] = 0xb0;
tapdev_init();
uip_init();
dhcpc_init(&uip_ethaddr,6);
dhcpc_request();
}
int UipPro(void)
{
int i;
if(1)
{
uip_len = tapdev_read();
if(uip_len > 0)
{
if(BUF->type == htons(UIP_ETHTYPE_IP))
{
uip_arp_ipin();
uip_input();
if(uip_len > 0)
{
uip_arp_out();
tapdev_send();
}
}
else if(BUF->type == htons(UIP_ETHTYPE_ARP))
{
uip_arp_arpin();
if(uip_len > 0)
{
tapdev_send();
}
}
}
else if(timer_expired(&periodic_timer))
{
timer_reset(&periodic_timer);
for(i = 0; i < UIP_CONNS; i++)
{
uip_periodic(i);
if(uip_len > 0)
{
uip_arp_out();
tapdev_send();
}
}
#if UIP_UDP
for(i = 0; i < UIP_UDP_CONNS; i++)
{
uip_udp_periodic(i);
if(uip_len > 0)
{
uip_arp_out();
tapdev_send();
}
}
#endif /* UIP_UDP */
/* Call the ARP timer function every 10 seconds. */
if(timer_expired(&arp_timer))
{
timer_reset(&arp_timer);
uip_arp_timer();
}
}
}
return 0;
}
int main(int argc, char* argv[])
{
uIP_Net_Init();
while(1)
{
UipPro();
}
return 0;
}
通过DHCP获取动态IP,接可以在同一台机器上测试了。
注:winpcap不能抓自己发给自己的数据包,需要把本机IP加入路由表,但加入后,本地TCP通讯又不正常了。