赞
踩
ICMP(Internet Control Message Protocol,英特网控制报文协议),常用于网络的调试与维护. ICMP通常被认为是IP层协议的一部分,但从体系结构上,它是位于IP层之上。
图1
Ping命令使用的就是ICMP的查询报文,如果能ping成功,说明网卡、IP层、ICMP层是能正常通信的。
对于RT1060,可以支持ICMP的硬件checksum插入,所涉及的控制寄存器相关位为:
图2
那么,如何在现有的RT1060 LWIP SDK ping工程中加入ICMP的硬件checksum呢?SDK ping工程默认是使用软件checksum。如果要测试ICMP硬件checksum的插入,首先需要关闭软件checksum,然后才能通过配置RT1060 ENET IP的TACC寄存器中的IPCHK, PROCHK 位去使能硬件checksum。IPCHK控制的是IP头checksum,PROCHK控制的是message protocol checksum。
小编在测试的时候,遇到了一些坑,开始只是简单的使能了lwipopts.h中的CHECKSUM_BY_HARDWARE宏,认为该宏是直接控制所有的软硬件checksum选择,但是测试发现该宏只能去掉软件ICMP报文中的IP checksum,但是报文中的message protocol的checksum还是存在,这种情况只能测试IP硬件checksum的插入,无法测试message protocol 硬件checksum的插入,就像下图一样:
图 3
可以发现,报文中IP checksum已经关闭,但是message protocol的checksum依旧存在。所以本篇文章旨在如何在官方SDK lwip ping工程中实现ICMP硬件checksum的插入。
代码:
\SDK_2_14_0_EVK-MIMXRT1060\boards\evkmimxrt1060\lwip_examples\lwip_ping\freertos
开发板:
MIMXRT1060-EVK
1)lwipopts.h
#define CHECKSUM_BY_HARDWARE #ifdef CHECKSUM_BY_HARDWARE /* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/ #define CHECKSUM_GEN_IP 0 /* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/ #define CHECKSUM_GEN_UDP 0 /* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/ #define CHECKSUM_GEN_TCP 0 /* CHECKSUM_GEN_ICMP==0: Generate checksums in hardware for outgoing ICMP packets.*/ #define CHECKSUM_GEN_ICMP 0 /* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/ #define CHECKSUM_CHECK_IP 0 /* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/ #define CHECKSUM_CHECK_UDP 0 /* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/ #define CHECKSUM_CHECK_TCP 0 /* CHECKSUM_GEN_ICMP==0: Generate checksums in hardware for incoming ICMP packets.*/ #define CHECKSUM_CHECK_ICMP 0 #else /* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/ #define CHECKSUM_GEN_IP 1 /* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/ #define CHECKSUM_GEN_UDP 1 /* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/ #define CHECKSUM_GEN_TCP 1 /* CHECKSUM_GEN_ICMP==1: Generate checksums in software for outgoing ICMP packets.*/ #define CHECKSUM_GEN_ICMP 1 /* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/ #define CHECKSUM_CHECK_IP 1 /* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/ #define CHECKSUM_CHECK_UDP 1 /* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/ #define CHECKSUM_CHECK_TCP 1 /* CHECKSUM_CHECK_ICMP==1: Check checksums in software for incoming ICMP packets.*/ #define CHECKSUM_CHECK_ICMP 1 #endif
图 4
2)enet_ethernetif_kinetis.c, ethernetif_plat_init函数
void ethernetif_plat_init(struct netif *netif, struct ethernetif *ethernetif, const ethernetif_config_t *ethernetifConfig) { enet_config_t config; enet_buffer_config_t buffCfg[ETHERNETIF_RING_NUM]; int i; .... ENET_GetDefaultConfig(&config); config.ringNum = ETHERNETIF_RING_NUM; config.rxBuffAlloc = ethernetif_rx_alloc; config.rxBuffFree = ethernetif_rx_free; config.userData = netif; #ifdef CHECKSUM_BY_HARDWARE //config.txAccelerConfig = (uint32_t)kENET_TxAccelIpCheckEnabled | (uint32_t)kENET_TxAccelProtoCheckEnabled; #endif /* Used for detection of change. Initilize to value different than any possible enum value. */ ethernetif->last_speed = (phy_speed_t)0xa5a5; ethernetif->last_duplex = (phy_duplex_t)0x5a5a; ethernetif->last_link_up = false;
图 5
这里主要是为了配置寄存器使能硬件IP和protocol checksum,如图2所示。
3)ping.c,ping_prepare_echo函数
/** Prepare a echo ICMP request */ static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len) { size_t i; size_t data_len = len - sizeof(struct icmp_echo_hdr); ICMPH_TYPE_SET(iecho, ICMP_ECHO); ICMPH_CODE_SET(iecho, 0); iecho->chksum = 0; iecho->id = PING_ID; iecho->seqno = lwip_htons(++ping_seq_num); /* fill the additional data buffer with some data */ for(i = 0; i < data_len; i++) { ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; } // iecho->chksum = inet_chksum(iecho, len); #ifndef CHECKSUM_BY_HARDWARE //kerry add iecho->chksum = inet_chksum(iecho, len); #endif }
图 6
对于iecho->chksum = inet_chksum(iecho, len);添加硬件checksum的宏判断,如果是硬件checksum,则不需要运行软件的checksum计算,否则会导致ICMP 报文中依旧会有protocol checksum的值。
至此,修改点已经全部完毕。
首先测试去除软件checksum,并且不添加硬件ICMP checksum使能的情况,也就是在上面修改代码的基础上屏蔽代码:
config.txAccelerConfig = (uint32_t)kENET_TxAccelIpCheckEnabled | (uint32_t)kENET_TxAccelProtoCheckEnabled;
测试结果如下:
图 7
可以看到,当关闭软件checksum,但是还没有使能硬件checksum的寄存器的时候,抓到的ICMP 报文的IP checksum和message protocol checksum没有被添加,是错误的状态。
下面在enet_ethernetif_kinetis.c文件中, ethernetif_plat_init函数加回:
config.txAccelerConfig = (uint32_t)kENET_TxAccelIpCheckEnabled | (uint32_t)kENET_TxAccelProtoCheckEnabled;
测试结果如下:
图 8
可以看到,这个时候,在软件ICMP checksum关闭的情况下,硬件的IPCHK,PROCHK位使能,已经能够在ICMP 报文中插入硬件的checksum,包括IP header checksum和message protocol checksum。
综上,经过SDK代码的修改,能够实现RT1060 ICMP IP 和message protocol 硬件checksum的添加。
希望小小经验对大家有所帮助.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。