Fix ICMP ping. Obey timeout.

This commit is contained in:
Shawn Hoffman 2012-02-17 00:41:31 -08:00
parent 2d5e80d36c
commit 570a12dcd1
3 changed files with 78 additions and 37 deletions

View File

@ -6,5 +6,5 @@
#include "Common.h"
int icmp_echo_req(u32 s, sockaddr_in *addr, u8 *data, u32 data_length);
int icmp_echo_rep(u32 s, sockaddr_in *addr, const 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(const u32 s, sockaddr_in *addr, const u32 timeout, const u32 data_length);

View File

@ -8,7 +8,6 @@ enum
enum
{
// id/seq/data come from wii
ICMP_HDR_LEN = 4,
IP_HDR_LEN = 20
};
@ -35,7 +34,7 @@ static u8 workspace[56];
* NOTE: to handle odd number of bytes, last (even) byte in
* 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;
@ -51,7 +50,7 @@ u16 cksum(u16 *buffer, int length)
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));
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);
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));
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));
int addr_length = sizeof(sockaddr_in);
int ret = recvfrom((SOCKET)s, (LPSTR)workspace,
int num_bytes = 0;
fd_set read_fds;
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?
return ret;
if (num_bytes >= IP_HDR_LEN + ICMP_HDR_LEN)
num_bytes -= IP_HDR_LEN + ICMP_HDR_LEN;
}
return num_bytes;
}

View File

@ -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");
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)
WARN_LOG(WII_IPC_NET, "NET_KD_REQ: IOCTL_NWC24_REQUEST_GENERATED_USER_ID");
//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)",
sock, _BufferIn, BufferInSize, _BufferOut, BufferOutSize);
struct sockaddr sa;
sockaddr sa;
socklen_t sa_len;
sa_len = sizeof(sa);
int ret = getsockname(sock, &sa, &sa_len);
Memory::Write_U8(BufferOutSize, _BufferOut);
Memory::Write_U8(sa.sa_family & 0xFF, _BufferOut+1);
Memory::WriteBigEData((u8*)&sa.sa_data, _BufferOut+2, BufferOutSize-2);
Memory::Write_U8(sa.sa_family & 0xFF, _BufferOut + 1);
Memory::WriteBigEData((u8*)&sa.sa_data, _BufferOut + 2, BufferOutSize - 2);
return ret;
}
case IOCTL_SO_GETPEERNAME:
{
u32 sock = Memory::Read_U32(_BufferIn);
WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETPEERNAME "
"Socket: %08X, BufferIn: (%08x, %i), BufferOut: (%08x, %i)",
sock, _BufferIn, BufferInSize, _BufferOut, BufferOutSize);
struct sockaddr sa;
sockaddr sa;
socklen_t sa_len;
sa_len = sizeof(sa);
int ret = getpeername(sock, &sa, &sa_len);
Memory::Write_U8(BufferOutSize, _BufferOut);
Memory::Write_U8(sa.sa_family & 0xFF, _BufferOut+1);
Memory::WriteBigEData((u8*)&sa.sa_data, _BufferOut+2, BufferOutSize-2);
Memory::Write_U8(AF_INET, _BufferOut + 1);
Memory::WriteBigEData((u8*)&sa.sa_data, _BufferOut + 2, BufferOutSize - 2);
WARN_LOG(WII_IPC_NET, "IOCTL_SO_GETPEERNAME(%x)", sock);
return ret;
}
case 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?
u32 arg = Memory::Read_U32(_BufferIn);
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);
}
@ -1005,7 +1012,7 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommand(u32 _Command,
{
u32 sock = Memory::Read_U32(_BufferIn);
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);
}
@ -1396,7 +1403,7 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer
{
u8 length;
u8 addr_family;
u16 port;
u16 icmp_id;
u32 ip;
} 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.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);
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"
"length %x addr_family %x port %x",
ip_info.length, ip_info.addr_family, ip_info.port);
"length %x addr_family %x",
ip_info.length, ip_info.addr_family);
}
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_addr.S_un.S_addr = Common::swap32(ip_info.ip);
memset(addr.sin_zero, 0, 8);
u8 *data = Memory::GetPointer(_BufferIn2);
int ret = icmp_echo_req(sock, &addr, data, BufferInSize2);
if (ret >= 0)
u8 data[0x20];
memset(data, 0, sizeof(data));
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
return 0;
}