已经确认UDP不能用是校验和的计算有问题,怀疑TCP不能用也是校验和的问题

测试仍然未通过
This commit is contained in:
Stone 2014-11-16 17:28:02 +00:00
parent 6364194c84
commit cccf7bfe6f
6 changed files with 55 additions and 35 deletions

View File

@ -203,8 +203,8 @@ typedef struct _UDP_HEADER
{
ushort SrcPort; // 远端口号
ushort DestPort; // 目的端口号
ushort Length; // udp头部长度
ushort Checksum; // 16位udp检验和
ushort Length; // 头部加上负载的总长度
ushort Checksum; // 检验和
void Init(bool recursion = false)
{

View File

@ -122,7 +122,7 @@ bool IcmpSocket::Ping(IPAddress ip, uint payloadLength)
icmp->Sequence = seq;
icmp->Checksum = 0;
icmp->Checksum = __REV16((ushort)TinyIP::CheckSum((byte*)icmp, sizeof(ICMP_HEADER) + payloadLength, 0));
icmp->Checksum = __REV16(Tip->CheckSum((byte*)icmp, sizeof(ICMP_HEADER) + payloadLength, 0));
#if NET_DEBUG
debug_printf("Ping ");

View File

@ -127,16 +127,17 @@ bool TcpSocket::Process(MemoryStream* ms)
void TcpSocket::Send(TCP_HEADER* tcp, uint len, byte flags)
{
Tip->RemoteIP = RemoteIP;
tcp->SrcPort = __REV16(Port);
tcp->DestPort = __REV16(RemotePort);
tcp->Flags = flags;
if(tcp->Length < sizeof(TCP_HEADER) / 4) tcp->Length = sizeof(TCP_HEADER) / 4;
// 必须在校验码之前设置,因为计算校验码需要地址
Tip->RemoteIP = RemoteIP;
// 网络序是大端
tcp->Checksum = 0;
tcp->Checksum = __REV16((ushort)TinyIP::CheckSum((byte*)tcp - 8, 8 + sizeof(TCP_HEADER) + len, 2));
tcp->Checksum = __REV16(Tip->CheckSum((byte*)tcp, tcp->Size() + len, 2));
debug_printf("SendTcp: Flags=0x%02x, len=%d(0x%x) %d => %d \r\n", flags, tcp->Length, tcp->Length, __REV16(tcp->SrcPort), __REV16(tcp->DestPort));

View File

@ -306,9 +306,13 @@ void TinyIP::SendIP(IP_TYPE type, byte* buf, uint len)
//ip->TTL = 64;
ip->Protocol = type;
// 报文唯一标识。用于识别重组等
static ushort g_Identifier = 1;
ip->Identifier = __REV16(g_Identifier++);
// 网络序是大端
ip->Checksum = 0;
ip->Checksum = __REV16((ushort)TinyIP::CheckSum((byte*)ip, sizeof(IP_HEADER), 0));
ip->Checksum = __REV16(CheckSum((byte*)ip, sizeof(IP_HEADER), 0));
assert_ptr(Arp);
ArpSocket* arp = (ArpSocket*)Arp;
@ -359,47 +363,52 @@ void TinyIP::ShowMac(const MacAddress& mac)
debug_printf("-%02X", *m++);
}
uint TinyIP::CheckSum(byte* buf, uint len, byte type)
ushort TinyIP::CheckSum(byte* buf, uint len, byte type)
{
// type 0=ip
// 1=udp
// 2=tcp
unsigned long sum = 0;
uint sum = 0;
if(type == 1)
{
sum += IP_UDP; // protocol udp
// the length here is the length of udp (data+header len)
// =length given to this function - (IP.scr+IP.dst length)
sum += len - 8; // = real tcp len
}
if(type == 2)
{
sum += IP_TCP;
// the length here is the length of tcp (data+header len)
// =length given to this function - (IP.scr+IP.dst length)
sum += len - 8; // = real tcp len
}
// build the sum of 16bit words
// !!谨记网络是大端
if(type == 1 || type == 2)
{
// UDP/TCP的校验和需要计算UDP首部加数据荷载部分但也需要加上UDP伪首部。
// 这个伪首部指源地址、目的地址、UDP数据长度、协议类型0x11协议类型就一个字节但需要补一个字节的0x0构成12个字节。
// 源地址。其实可以按照4字节累加反正后面会把高位移位到低位累加但是得考虑溢出的问题。
sum += __REV16(IP & 0xFFFF);
sum += __REV16(IP >> 16);
sum += __REV16(RemoteIP & 0xFFFF);
sum += __REV16(RemoteIP >> 16);
// 数据长度
sum += len;
// 加上协议类型
if(type == 1)
sum += IP_UDP;
else if(type == 2)
sum += IP_TCP;
}
// 按16位字计算和
while(len > 1)
{
sum += 0xFFFF & (*buf << 8 | *(buf + 1));
buf += 2;
len -= 2;
}
// if there is a byte left then add it (padded with zero)
// 如果字节个数不是偶数个这里会剩余1后面补0
if (len)
{
sum += (0xFF & *buf) << 8;
}
// now calculate the sum over the bytes in the sum
// until the result is only 16bit long
while (sum>>16)
// 现在计算sum字节的和直到只有16位长
while (sum >> 16)
{
sum = (sum & 0xFFFF) + (sum >> 16);
}
// build 1's complement:
return( (uint) sum ^ 0xFFFF);
// 取补码
return (ushort)(sum ^ 0xFFFF);
}
bool TinyIP::IsMyIP(IPAddress ip)

View File

@ -91,7 +91,7 @@ public:
void ShowInfo();
static void ShowIP(IPAddress ip);
static void ShowMac(const MacAddress& mac);
static uint CheckSum(byte* buf, uint len, byte type);
ushort CheckSum(byte* buf, uint len, byte type);
void SendEthernet(ETH_TYPE type, byte* buf, uint len);
void SendIP(IP_TYPE type, byte* buf, uint len);

View File

@ -1,5 +1,7 @@
#include "Udp.h"
#define NET_DEBUG DEBUG
UdpSocket::UdpSocket(TinyIP* tip) : Socket(tip)
{
Type = IP_UDP;
@ -74,6 +76,13 @@ void UdpSocket::OnProcess(UDP_HEADER* udp, MemoryStream& ms)
uint len = __REV16(udp->Length) - sizeof(UDP_HEADER);
assert_param(len <= ms.Remain());
#if NET_DEBUG
ushort oldsum = __REV16(udp->Checksum);
udp->Checksum = 0;
udp->Checksum = __REV16(Tip->CheckSum((byte*)udp, sizeof(UDP_HEADER) + len, 1));
debug_printf("UDP::Checksum ori=0x%02x new=0x%02x\r\n", oldsum, __REV16(udp->Checksum));
#endif
// 触发ITransport接口事件
uint len2 = OnReceive(data, len);
// 如果有返回,说明有数据要回复出去
@ -111,11 +120,12 @@ void UdpSocket::Send(UDP_HEADER* udp, uint len, bool checksum)
udp->DestPort = __REV16(RemotePort);
udp->Length = __REV16(sizeof(UDP_HEADER) + len);
// 必须在校验码之前设置,因为计算校验码需要地址
Tip->RemoteIP = RemoteIP;
// 网络序是大端
udp->Checksum = 0;
if(checksum) udp->Checksum = __REV16((ushort)TinyIP::CheckSum((byte*)udp, sizeof(UDP_HEADER) + len, 1));
Tip->RemoteIP = RemoteIP;
if(checksum) udp->Checksum = __REV16(Tip->CheckSum((byte*)udp, sizeof(UDP_HEADER) + len, 1));
debug_printf("SendUdp: len=%d(0x%x) %d => %d \r\n", udp->Length, udp->Length, __REV16(udp->SrcPort), __REV16(udp->DestPort));
@ -148,7 +158,7 @@ void UdpSocket::Send(const byte* buf, uint len, IPAddress ip, ushort port)
memcpy(udp->Next(), buf, len);
}
Send(udp, len, false);
Send(udp, len, true);
}
bool UdpSocket::OnWrite(const byte* buf, uint len)