Fix ICMP ping. Obey timeout.
This commit is contained in:
parent
2d5e80d36c
commit
570a12dcd1
|
@ -6,5 +6,5 @@
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
int icmp_echo_req(u32 s, sockaddr_in *addr, u8 *data, u32 data_length);
|
int icmp_echo_req(const u32 s, const sockaddr_in *addr, const u8 *data, const u32 data_length);
|
||||||
int icmp_echo_rep(u32 s, sockaddr_in *addr, const u8 *data, u32 data_length);
|
int icmp_echo_rep(const u32 s, sockaddr_in *addr, const u32 timeout, const u32 data_length);
|
||||||
|
|
|
@ -8,7 +8,6 @@ enum
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
// id/seq/data come from wii
|
|
||||||
ICMP_HDR_LEN = 4,
|
ICMP_HDR_LEN = 4,
|
||||||
IP_HDR_LEN = 20
|
IP_HDR_LEN = 20
|
||||||
};
|
};
|
||||||
|
@ -35,8 +34,8 @@ static u8 workspace[56];
|
||||||
* NOTE: to handle odd number of bytes, last (even) byte in
|
* NOTE: to handle odd number of bytes, last (even) byte in
|
||||||
* buffer have a value of 0 (we assume that it does)
|
* buffer have a value of 0 (we assume that it does)
|
||||||
*/
|
*/
|
||||||
u16 cksum(u16 *buffer, int length)
|
u16 cksum(const u16 *buffer, int length)
|
||||||
{
|
{
|
||||||
u32 sum = 0;
|
u32 sum = 0;
|
||||||
|
|
||||||
while (length > 0)
|
while (length > 0)
|
||||||
|
@ -51,7 +50,7 @@ u16 cksum(u16 *buffer, int length)
|
||||||
return (u16)~sum;
|
return (u16)~sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
int icmp_echo_req(u32 s, sockaddr_in *addr, u8 *data, u32 data_length)
|
int icmp_echo_req(const u32 s, const sockaddr_in *addr, const u8 *data, const u32 data_length)
|
||||||
{
|
{
|
||||||
memset(workspace, 0, sizeof(workspace));
|
memset(workspace, 0, sizeof(workspace));
|
||||||
icmp_hdr *header = (icmp_hdr *)workspace;
|
icmp_hdr *header = (icmp_hdr *)workspace;
|
||||||
|
@ -62,18 +61,38 @@ int icmp_echo_req(u32 s, sockaddr_in *addr, u8 *data, u32 data_length)
|
||||||
|
|
||||||
header->checksum = cksum((u16 *)header, ICMP_HDR_LEN + data_length);
|
header->checksum = cksum((u16 *)header, ICMP_HDR_LEN + data_length);
|
||||||
|
|
||||||
return sendto((SOCKET)s, (LPSTR)header, ICMP_HDR_LEN + data_length, 0,
|
int num_bytes = sendto((SOCKET)s, (LPSTR)header, ICMP_HDR_LEN + data_length, 0,
|
||||||
(sockaddr *)addr, sizeof(sockaddr));
|
(sockaddr *)addr, sizeof(sockaddr));
|
||||||
|
|
||||||
|
if (num_bytes >= ICMP_HDR_LEN)
|
||||||
|
num_bytes -= ICMP_HDR_LEN;
|
||||||
|
|
||||||
|
return num_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
int icmp_echo_rep(u32 s, sockaddr_in *addr, const u8 *data, u32 data_length)
|
int icmp_echo_rep(const u32 s, sockaddr_in *addr, const u32 timeout, const u32 data_length)
|
||||||
{
|
{
|
||||||
memset(workspace, 0, sizeof(workspace));
|
memset(workspace, 0, sizeof(workspace));
|
||||||
int addr_length = sizeof(sockaddr_in);
|
int addr_length = sizeof(sockaddr_in);
|
||||||
int ret = recvfrom((SOCKET)s, (LPSTR)workspace,
|
int num_bytes = 0;
|
||||||
IP_HDR_LEN + ICMP_HDR_LEN + data_length,
|
|
||||||
0, (sockaddr *)addr, &addr_length);
|
|
||||||
|
|
||||||
// TODO do we need to memcmp the data?
|
fd_set read_fds;
|
||||||
return ret;
|
FD_ZERO(&read_fds);
|
||||||
|
FD_SET(s, &read_fds);
|
||||||
|
|
||||||
|
timeval t;
|
||||||
|
t.tv_sec = timeout / 1000;
|
||||||
|
if (select(0, &read_fds, NULL, NULL, &t) > 0)
|
||||||
|
{
|
||||||
|
num_bytes = recvfrom((SOCKET)s, (LPSTR)workspace,
|
||||||
|
IP_HDR_LEN + ICMP_HDR_LEN + data_length,
|
||||||
|
0, (sockaddr *)addr, &addr_length);
|
||||||
|
|
||||||
|
// TODO do we need to memcmp the data?
|
||||||
|
|
||||||
|
if (num_bytes >= IP_HDR_LEN + ICMP_HDR_LEN)
|
||||||
|
num_bytes -= IP_HDR_LEN + ICMP_HDR_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_bytes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,12 @@ bool CWII_IPC_HLE_Device_net_kd_request::IOCtl(u32 _CommandAddress)
|
||||||
WARN_LOG(WII_IPC_NET, "NET_KD_REQ: IOCTL_NWC24_UNLOCK_SOCKET - NI");
|
WARN_LOG(WII_IPC_NET, "NET_KD_REQ: IOCTL_NWC24_UNLOCK_SOCKET - NI");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IOCTL_NWC24_REQUEST_REGISTER_USER_ID:
|
||||||
|
WARN_LOG(WII_IPC_NET, "NET_KD_REQ: IOCTL_NWC24_REQUEST_REGISTER_USER_ID");
|
||||||
|
Memory::Write_U32(0, BufferOut);
|
||||||
|
Memory::Write_U32(0, BufferOut+4);
|
||||||
|
break;
|
||||||
|
|
||||||
case IOCTL_NWC24_REQUEST_GENERATED_USER_ID: // (Input: none, Output: 32 bytes)
|
case IOCTL_NWC24_REQUEST_GENERATED_USER_ID: // (Input: none, Output: 32 bytes)
|
||||||
WARN_LOG(WII_IPC_NET, "NET_KD_REQ: IOCTL_NWC24_REQUEST_GENERATED_USER_ID");
|
WARN_LOG(WII_IPC_NET, "NET_KD_REQ: IOCTL_NWC24_REQUEST_GENERATED_USER_ID");
|
||||||
//Memory::Write_U32(0xFFFFFFDC, BufferOut);
|
//Memory::Write_U32(0xFFFFFFDC, BufferOut);
|
||||||
|
@ -817,34 +823,35 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommand(u32 _Command,
|
||||||
"Socket: %08X, BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
|
"Socket: %08X, BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
|
||||||
sock, _BufferIn, BufferInSize, _BufferOut, BufferOutSize);
|
sock, _BufferIn, BufferInSize, _BufferOut, BufferOutSize);
|
||||||
|
|
||||||
struct sockaddr sa;
|
sockaddr sa;
|
||||||
socklen_t sa_len;
|
socklen_t sa_len;
|
||||||
sa_len = sizeof(sa);
|
sa_len = sizeof(sa);
|
||||||
int ret = getsockname(sock, &sa, &sa_len);
|
int ret = getsockname(sock, &sa, &sa_len);
|
||||||
|
|
||||||
Memory::Write_U8(BufferOutSize, _BufferOut);
|
Memory::Write_U8(BufferOutSize, _BufferOut);
|
||||||
Memory::Write_U8(sa.sa_family & 0xFF, _BufferOut+1);
|
Memory::Write_U8(sa.sa_family & 0xFF, _BufferOut + 1);
|
||||||
Memory::WriteBigEData((u8*)&sa.sa_data, _BufferOut+2, BufferOutSize-2);
|
Memory::WriteBigEData((u8*)&sa.sa_data, _BufferOut + 2, BufferOutSize - 2);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
case IOCTL_SO_GETPEERNAME:
|
case IOCTL_SO_GETPEERNAME:
|
||||||
{
|
{
|
||||||
u32 sock = Memory::Read_U32(_BufferIn);
|
u32 sock = Memory::Read_U32(_BufferIn);
|
||||||
|
|
||||||
WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETPEERNAME "
|
sockaddr sa;
|
||||||
"Socket: %08X, BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
|
|
||||||
sock, _BufferIn, BufferInSize, _BufferOut, BufferOutSize);
|
|
||||||
|
|
||||||
struct sockaddr sa;
|
|
||||||
socklen_t sa_len;
|
socklen_t sa_len;
|
||||||
sa_len = sizeof(sa);
|
sa_len = sizeof(sa);
|
||||||
|
|
||||||
int ret = getpeername(sock, &sa, &sa_len);
|
int ret = getpeername(sock, &sa, &sa_len);
|
||||||
|
|
||||||
Memory::Write_U8(BufferOutSize, _BufferOut);
|
Memory::Write_U8(BufferOutSize, _BufferOut);
|
||||||
Memory::Write_U8(sa.sa_family & 0xFF, _BufferOut+1);
|
Memory::Write_U8(AF_INET, _BufferOut + 1);
|
||||||
Memory::WriteBigEData((u8*)&sa.sa_data, _BufferOut+2, BufferOutSize-2);
|
Memory::WriteBigEData((u8*)&sa.sa_data, _BufferOut + 2, BufferOutSize - 2);
|
||||||
|
|
||||||
|
WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETPEERNAME(%x)", sock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IOCTL_SO_GETHOSTID:
|
case IOCTL_SO_GETHOSTID:
|
||||||
{
|
{
|
||||||
WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETHOSTID "
|
WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETHOSTID "
|
||||||
|
@ -993,7 +1000,7 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommand(u32 _Command,
|
||||||
// AF type?
|
// AF type?
|
||||||
u32 arg = Memory::Read_U32(_BufferIn);
|
u32 arg = Memory::Read_U32(_BufferIn);
|
||||||
u32 sock = (u32)socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
u32 sock = (u32)socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||||
ERROR_LOG(WII_IPC_NET, "IOCTL_SO_ICMPSOCKET(%x) %x", arg, sock);
|
DEBUG_LOG(WII_IPC_NET, "IOCTL_SO_ICMPSOCKET(%x) %x", arg, sock);
|
||||||
return getNetErrorCode(sock, "IOCTL_SO_ICMPSOCKET", false);
|
return getNetErrorCode(sock, "IOCTL_SO_ICMPSOCKET", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,7 +1012,7 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommand(u32 _Command,
|
||||||
{
|
{
|
||||||
u32 sock = Memory::Read_U32(_BufferIn);
|
u32 sock = Memory::Read_U32(_BufferIn);
|
||||||
u32 ret = closesocket(sock);
|
u32 ret = closesocket(sock);
|
||||||
ERROR_LOG(WII_IPC_NET, "IOCTL_SO_ICMPCLOSE(%x) %x", sock, ret);
|
DEBUG_LOG(WII_IPC_NET, "IOCTL_SO_ICMPCLOSE(%x) %x", sock, ret);
|
||||||
return getNetErrorCode(ret, "IOCTL_SO_ICMPCLOSE", false);
|
return getNetErrorCode(ret, "IOCTL_SO_ICMPCLOSE", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1396,7 +1403,7 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer
|
||||||
{
|
{
|
||||||
u8 length;
|
u8 length;
|
||||||
u8 addr_family;
|
u8 addr_family;
|
||||||
u16 port;
|
u16 icmp_id;
|
||||||
u32 ip;
|
u32 ip;
|
||||||
} ip_info;
|
} ip_info;
|
||||||
|
|
||||||
|
@ -1411,14 +1418,14 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer
|
||||||
|
|
||||||
ip_info.length = Memory::Read_U8(_BufferIn + 16);
|
ip_info.length = Memory::Read_U8(_BufferIn + 16);
|
||||||
ip_info.addr_family = Memory::Read_U8(_BufferIn + 17);
|
ip_info.addr_family = Memory::Read_U8(_BufferIn + 17);
|
||||||
ip_info.port = Memory::Read_U16(_BufferIn + 18);
|
ip_info.icmp_id = Memory::Read_U16(_BufferIn + 18);
|
||||||
ip_info.ip = Memory::Read_U32(_BufferIn + 20);
|
ip_info.ip = Memory::Read_U32(_BufferIn + 20);
|
||||||
|
|
||||||
if (ip_info.length != 8 || ip_info.addr_family != AF_INET || ip_info.port != 0)
|
if (ip_info.length != 8 || ip_info.addr_family != AF_INET)
|
||||||
{
|
{
|
||||||
WARN_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING strange IPInfo:\n"
|
WARN_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING strange IPInfo:\n"
|
||||||
"length %x addr_family %x port %x",
|
"length %x addr_family %x",
|
||||||
ip_info.length, ip_info.addr_family, ip_info.port);
|
ip_info.length, ip_info.addr_family);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING %x", ip_info.ip);
|
DEBUG_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING %x", ip_info.ip);
|
||||||
|
@ -1427,13 +1434,28 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
addr.sin_addr.S_un.S_addr = Common::swap32(ip_info.ip);
|
addr.sin_addr.S_un.S_addr = Common::swap32(ip_info.ip);
|
||||||
memset(addr.sin_zero, 0, 8);
|
memset(addr.sin_zero, 0, 8);
|
||||||
u8 *data = Memory::GetPointer(_BufferIn2);
|
|
||||||
|
u8 data[0x20];
|
||||||
int ret = icmp_echo_req(sock, &addr, data, BufferInSize2);
|
memset(data, 0, sizeof(data));
|
||||||
if (ret >= 0)
|
u32 icmp_length = sizeof(data);
|
||||||
|
|
||||||
|
if (BufferInSize2 == sizeof(data))
|
||||||
|
memcpy(data, Memory::GetPointer(_BufferIn2), BufferInSize2);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
//icmp_echo_rep(sock, &addr, data, BufferInSize2);
|
// TODO sequence number is incremented either statically, by
|
||||||
|
// port, or by socket. Doesn't seem to matter, so we just leave
|
||||||
|
// it 0
|
||||||
|
((u16 *)data)[0] = Common::swap16(ip_info.icmp_id);
|
||||||
|
icmp_length = 22;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ret = icmp_echo_req(sock, &addr, data, icmp_length);
|
||||||
|
if (ret == icmp_length)
|
||||||
|
{
|
||||||
|
ret = icmp_echo_rep(sock, &addr, timeout, icmp_length);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO proper error codes
|
// TODO proper error codes
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue