diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index df209f43ce..dece999185 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -320,6 +320,7 @@ + @@ -520,6 +521,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 017c32f865..c05fba9a38 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -559,6 +559,9 @@ HW %28Flipper/Hollywood%29\GCMemcard + + IPC HLE %28IOS/Starlet%29\Net + @@ -1042,6 +1045,9 @@ IPC HLE %28IOS/Starlet%29\Net + + IPC HLE %28IOS/Starlet%29\Net + diff --git a/Source/Core/Core/Src/IPC_HLE/ICMP.h b/Source/Core/Core/Src/IPC_HLE/ICMP.h new file mode 100644 index 0000000000..abb99b9ded --- /dev/null +++ b/Source/Core/Core/Src/IPC_HLE/ICMP.h @@ -0,0 +1,10 @@ +#pragma once + +#ifdef _WIN32 +#include +#endif + +#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); diff --git a/Source/Core/Core/Src/IPC_HLE/ICMPWin.cpp b/Source/Core/Core/Src/IPC_HLE/ICMPWin.cpp new file mode 100644 index 0000000000..8c90ce3ea3 --- /dev/null +++ b/Source/Core/Core/Src/IPC_HLE/ICMPWin.cpp @@ -0,0 +1,79 @@ +#include "ICMP.h" + +enum +{ + ICMP_ECHOREPLY = 0, + ICMP_ECHOREQ = 8 +}; + +enum +{ + // id/seq/data come from wii + ICMP_HDR_LEN = 4, + IP_HDR_LEN = 20 +}; + +#pragma pack(push, 1) +struct icmp_hdr +{ + u8 type; + u8 code; + u16 checksum; + u16 id; + u16 seq; + char data[1]; +}; +#pragma pack(pop) + +static u8 workspace[56]; + +/* +* Description: +* Calculate Internet checksum for data buffer and length (one's +* complement sum of 16-bit words). Used in IP, ICMP, UDP, IGMP. +* +* 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) +{ + u32 sum = 0; + + while (length > 0) + { + sum += *(buffer++); + length -= 2; + } + + sum = (sum & 0xffff) + (sum >> 16); + sum += sum >> 16; + + return (u16)~sum; +} + +int icmp_echo_req(u32 s, sockaddr_in *addr, u8 *data, u32 data_length) +{ + memset(workspace, 0, sizeof(workspace)); + icmp_hdr *header = (icmp_hdr *)workspace; + header->type = ICMP_ECHOREQ; + header->code = 0; + header->checksum = 0; + memcpy(&header->id, data, data_length); + + header->checksum = cksum((u16 *)header, ICMP_HDR_LEN + data_length); + + return sendto((SOCKET)s, (LPSTR)header, ICMP_HDR_LEN + data_length, 0, + (sockaddr *)addr, sizeof(sockaddr)); +} + +int icmp_echo_rep(u32 s, sockaddr_in *addr, const u8 *data, u32 data_length) +{ + memset(workspace, 0, sizeof(workspace)); + int addr_length = sizeof(sockaddr_in); + int ret = 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; +} diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp index 8dc5fd4c19..c5361df01b 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp @@ -50,6 +50,7 @@ it failed) #include "FileUtil.h" #include #include +#include "ICMP.h" #ifdef _WIN32 #include @@ -969,10 +970,39 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommand(u32 _Command, break; } + case IOCTL_SO_ICMPSOCKET: + { + // 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); + return getNetErrorCode(sock, "IOCTL_SO_ICMPSOCKET", false); + } + + case IOCTL_SO_ICMPCANCEL: + ERROR_LOG(WII_IPC_NET, "IOCTL_SO_ICMPCANCEL"); + goto default_; + + case IOCTL_SO_ICMPCLOSE: + { + u32 sock = Memory::Read_U32(_BufferIn); + u32 ret = closesocket(sock); + ERROR_LOG(WII_IPC_NET, "IOCTL_SO_ICMPCLOSE(%x) %x", sock, ret); + return getNetErrorCode(ret, "IOCTL_SO_ICMPCLOSE", false); + } + default: WARN_LOG(WII_IPC_NET,"0x%x " "BufferIn: (%08x, %i), BufferOut: (%08x, %i)", _Command, _BufferIn, BufferInSize, _BufferOut, BufferOutSize); + default_: + if (BufferInSize) + { + ERROR_LOG(WII_IPC_NET, "in addr %x size %x", _BufferIn, BufferInSize); + ERROR_LOG(WII_IPC_NET, "\n%s", + ArrayToString(Memory::GetPointer(_BufferIn), BufferInSize, 4).c_str() + ); + } break; } @@ -980,7 +1010,7 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommand(u32 _Command, return 0; } -u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(u32 _Parameter, SIOCtlVBuffer CommandBuffer) +u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(SIOCtlVBuffer& CommandBuffer) { u32 _BufferIn = 0, _BufferIn2 = 0, _BufferIn3 = 0; u32 BufferInSize = 0, BufferInSize2 = 0, BufferInSize3 = 0; @@ -1036,7 +1066,7 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(u32 _Parameter, SIOCtlVBuffe u32 param = 0, param2 = 0, param3, param4, param5 = 0; - switch (_Parameter) + switch (CommandBuffer.Parameter) { case IOCTLV_SO_GETINTERFACEOPT: { @@ -1342,32 +1372,83 @@ u32 CWII_IPC_HLE_Device_net_ip_top::ExecuteCommandV(u32 _Parameter, SIOCtlVBuffe return ret; } + case IOCTLV_SO_ICMPPING: + { + struct + { + u8 length; + u8 addr_family; + u16 port; + u32 ip; + } ip_info; + + u32 sock = Memory::Read_U32(_BufferIn); + u32 num_ip = Memory::Read_U32(_BufferIn + 4); + u64 timeout = Memory::Read_U64(_BufferIn + 8); + + if (num_ip != 1) + { + WARN_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING %i IPs", num_ip); + } + + 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.ip = Memory::Read_U32(_BufferIn + 20); + + if (ip_info.length != 8 || ip_info.addr_family != AF_INET || ip_info.port != 0) + { + 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); + } + + DEBUG_LOG(WII_IPC_NET, "IOCTLV_SO_ICMPPING %x", ip_info.ip); + + sockaddr_in addr; + 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) + { + icmp_echo_rep(sock, &addr, data, BufferInSize2); + } + // TODO proper error codes + return 0; + } + default: WARN_LOG(WII_IPC_NET,"0x%x (BufferIn: (%08x, %i), BufferIn2: (%08x, %i)", - _Parameter, _BufferIn, BufferInSize, _BufferIn2, BufferInSize2); + CommandBuffer.Parameter, _BufferIn, BufferInSize, _BufferIn2, BufferInSize2); + default_: + for (int i = 0; i < CommandBuffer.NumberInBuffer; ++i) + { + ERROR_LOG(WII_IPC_NET, "in %i addr %x size %x", i, + CommandBuffer.InBuffer.at(i).m_Address, CommandBuffer.InBuffer.at(i).m_Size); + ERROR_LOG(WII_IPC_NET, "\n%s", + ArrayToString( + Memory::GetPointer(CommandBuffer.InBuffer.at(i).m_Address), + CommandBuffer.InBuffer.at(i).m_Size, 4).c_str() + ); + } + for (int i = 0; i < CommandBuffer.NumberPayloadBuffer; ++i) + { + ERROR_LOG(WII_IPC_NET, "out %i addr %x size %x", i, + CommandBuffer.PayloadBuffer.at(i).m_Address, CommandBuffer.PayloadBuffer.at(i).m_Size, 4); + } break; } + return 0; } -bool CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 _CommandAddress) +bool CWII_IPC_HLE_Device_net_ip_top::IOCtlV(u32 CommandAddress) { - u32 ReturnValue = 0; - SIOCtlVBuffer CommandBuffer(_CommandAddress); - switch (CommandBuffer.Parameter) - { - case IOCTLV_SO_SENDTO: - case IOCTL_SO_BIND: - case IOCTLV_SO_RECVFROM: - case IOCTL_SO_SOCKET: - case IOCTL_SO_GETHOSTID: - case IOCTL_SO_STARTUP: - default: - ReturnValue = ExecuteCommandV(CommandBuffer.Parameter, CommandBuffer); - break; - } - - Memory::Write_U32(ReturnValue, _CommandAddress+4); + u32 return_value = ExecuteCommandV(SIOCtlVBuffer(CommandAddress)); + Memory::Write_U32(return_value, CommandAddress + 4); return true; } diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.h index da5545a069..11e100c837 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.h @@ -409,7 +409,7 @@ private: }; u32 ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize); - u32 ExecuteCommandV(u32 _Parameter, SIOCtlVBuffer CommandBuffer); + u32 ExecuteCommandV(SIOCtlVBuffer& CommandBuffer); }; // **********************************************************************************