我知道此问题之前一定有问题,但我找不到合适的解决方案。
我正在Ubuntu 12.04上编写一个C程序,它使用原始套接字发送TCP数据包。计算校验和非常耗时,因此我尝试将其卸载到我的NIC。
struct sockaddr intfAddr
rawSock = socket(AF_INET,SOCK_PACKET,htons(3)); //ETH_P_ALL = 3
if (rawSock == -1) { perror("failed to create raw socket"); exit(-1); }
memset(&intfAddr, 0, sizeof (struct sockaddr));
intfAddr.sa_family = AF_INET;
strcpy(intfAddrs.sa_data, "eth0");
system("ifconfig eth0 promisc);
//sprintf(cmd, "ethtool -K %s rx off", intfName); system(cmd);
if (bind(rawSock, (struct sockaddr *)&intfAddr, sizeof(intfAddrs[intf])) == -1) {
perror("failed to bind"); exit(-1);
}
我从一台PC发送了TCP数据包,并使用wireshark捕获连接到发送PC的另一台PC上的数据包。 Wireshark可以捕获所有数据包但不幸的是TCP校验和不正确 - 发送PC的NIC没有进行校验和计算。如果我将TCP校验和设置为0,则wireshark将看到校验和为0的数据包。
这很令人困惑,因为发送PC上的linux命令“ethtool -k eth0”显示tx offload已打开。
$ ethtool -k eth0
Offload parameters for eth0:
rx-checksumming: on
tx-checksumming: on
scatter-gather: off
tcp-segmentation-offload: off
udp-fragmentation-offload: off
generic-segmentation-offload: off
generic-receive-offload: on
large-receive-offload: off
rx-vlan-offload: on
tx-vlan-offload: on
ntuple-filters: off
receive-hashing: off
有什么想法吗?谢谢!
答案 0 :(得分:0)
为什么使用ETH_P_ALL ?,尝试将htons(8)用于ETH_P_IP,而代码中的另一个问题是您正在使用数据包系列,PF用于在设备驱动程序处发送/接收数据(OSI)第2层),如果你要使用Packet系列和RAW_SOCK,你需要自己生成每个单独的头,所以尝试按如下方式创建套接字实例:
; IP header would be provided by the kernel
int s = socket (AF_INET, SOCK_RAW, IPPROTO_TCP);
; if you wanna use the Packet Family, do the following
sd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
在这种情况下,您必须自己提供标头并为校验和提供有关tcp伪标头的研究并使用此函数进行计算
unsigned short csum(unsigned short *buf, int nwords)
{ //
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
祝你好运:)