diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index 5e892dfc7b..c1e26463b5 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -228,6 +228,8 @@ void addFriend(SceNetAdhocctlConnectPacketS2C * packet) { peer->nickname = packet->name; peer->mac_addr = packet->mac; peer->ip_addr = packet->ip; + // Calculate final IP-specific Port Offset + peer->port_offset = ((isOriPort && !isPrivateIP(peer->ip_addr)) ? 0 : portOffset); // Update TimeStamp peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); } @@ -248,6 +250,9 @@ void addFriend(SceNetAdhocctlConnectPacketS2C * packet) { // Save IP Address peer->ip_addr = packet->ip; + // Calculate final IP-specific Port Offset + peer->port_offset = ((isOriPort && !isPrivateIP(peer->ip_addr)) ? 0 : portOffset); + // TimeStamp peer->last_recv = CoreTiming::GetGlobalTimeUsScaled(); @@ -2286,7 +2291,7 @@ bool resolveIP(uint32_t ip, SceNetEtherAddr * mac) { return false; } -bool resolveMAC(SceNetEtherAddr * mac, uint32_t * ip) { +bool resolveMAC(SceNetEtherAddr* mac, uint32_t* ip, u16* port_offset) { // Get Local MAC Address SceNetEtherAddr localMac; getLocalMac(&localMac); @@ -2296,6 +2301,8 @@ bool resolveMAC(SceNetEtherAddr * mac, uint32_t * ip) { sockaddr_in sockAddr; getLocalIp(&sockAddr); *ip = sockAddr.sin_addr.s_addr; + if (port_offset) + *port_offset = portOffset; return true; // return succes } @@ -2311,7 +2318,8 @@ bool resolveMAC(SceNetEtherAddr * mac, uint32_t * ip) { if (isMacMatch(&peer->mac_addr, mac)) { // Copy Data *ip = peer->ip_addr; - + if (port_offset) + *port_offset = peer->port_offset; // Return Success return true; } diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index 5b54492f0d..15b37675ba 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -294,11 +294,12 @@ typedef struct SceNetAdhocctlPeerInfo { SceNetAdhocctlPeerInfo * next; SceNetAdhocctlNickname nickname; SceNetEtherAddr mac_addr; - u16_le padding; + u16_le padding; // a copy of the padding(?) from SceNetAdhocctlPeerInfoEmu u32_le flags; u64_le last_recv; // Need to use the same method with sceKernelGetSystemTimeWide (ie. CoreTiming::GetGlobalTimeUsScaled) to prevent timing issue (ie. in game timeout) u32_le ip_addr; // internal use only + u16_le port_offset; // IP-specific port offset (internal use only) } PACK SceNetAdhocctlPeerInfo; // Peer Information with u32 pointers @@ -306,7 +307,7 @@ typedef struct SceNetAdhocctlPeerInfoEmu { u32_le next; // Changed the pointer to u32 SceNetAdhocctlNickname nickname; SceNetEtherAddr mac_addr; - u16_le padding; //00 00 + u16_le padding; //00 00 // Note: Not sure whether this is really padding or reserved/unknown field u32_le flags; //00 04 00 00 on KHBBS and FF FF FF FF on Ys vs. Sora no Kiseki // State of the peer? Or related to sceNetAdhocAuth_CF4D9BED ? u64_le last_recv; // Need to use the same method with sceKernelGetSystemTimeWide (ie. CoreTiming::GetGlobalTimeUsScaled) to prevent timing issue (ie. in game timeout) } PACK SceNetAdhocctlPeerInfoEmu; @@ -1448,9 +1449,10 @@ bool resolveIP(uint32_t ip, SceNetEtherAddr * mac); * Resolve MAC to IP * @param mac Peer MAC Address * @param ip OUT: Peer IP + * @param port_offset OUT: Peer IP-specific Port Offset * @return true on success */ -bool resolveMAC(SceNetEtherAddr * mac, uint32_t * ip); +bool resolveMAC(SceNetEtherAddr* mac, uint32_t* ip, u16* port_offset = nullptr); /** * Check whether Network Name contains only valid symbols diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index a6808fc473..88ef52c724 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -603,7 +603,7 @@ int DoBlockingPdpSend(int uid, AdhocSocketRequest& req, s64& result, AdhocSendTa struct sockaddr_in target {}; target.sin_family = AF_INET; target.sin_addr.s_addr = peer->ip; - target.sin_port = htons(peer->port + ((isOriPort && !isPrivateIP(peer->ip)) ? 0 : portOffset)); + target.sin_port = htons(peer->port + peer->portOffset); int ret = sendto(pdpsocket.id, (const char*)req.buffer, targetPeers.length, MSG_NOSIGNAL, (struct sockaddr*)&target, sizeof(target)); int sockerr = errno; @@ -1580,11 +1580,11 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int struct sockaddr_in target {}; target.sin_family = AF_INET; target.sin_port = htons(dport + portOffset); + u16 finalPortOffset; // Get Peer IP. Some games (ie. Vulcanus Seek and Destroy) seems to try to send to zero-MAC (ie. 00:00:00:00:00:00) first before sending to the actual destination MAC.. So may be sending to zero-MAC has a special meaning? (ie. to peek send buffer availability may be?) - if (resolveMAC((SceNetEtherAddr *)daddr, (uint32_t *)&target.sin_addr.s_addr)) { + if (resolveMAC((SceNetEtherAddr *)daddr, (uint32_t *)&target.sin_addr.s_addr, &finalPortOffset)) { // Some games (ie. PSP2) might try to talk to it's self, not sure if they talked through WAN or LAN when using public Adhoc Server tho - uint16_t finalPortOffset = ((isOriPort && !isPrivateIP(target.sin_addr.s_addr)) ? 0 : portOffset); target.sin_port = htons(dport + finalPortOffset); // Acquire Network Lock @@ -1604,7 +1604,7 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int } AdhocSendTargets dest = { len, {}, false }; - dest.peers.push_back({ target.sin_addr.s_addr, dport }); + dest.peers.push_back({ target.sin_addr.s_addr, dport, finalPortOffset }); sendTargetPeers[threadSocketId] = dest; return WaitBlockingAdhocSocket(threadSocketId, PDP_SEND, id, data, nullptr, timeout, nullptr, nullptr, "pdp send"); } @@ -1665,7 +1665,7 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int if (peer->last_recv == 0) continue; - dest.peers.push_back({ peer->ip_addr, dport }); + dest.peers.push_back({ peer->ip_addr, dport, peer->port_offset }); } // Free Peer Lock peerlock.unlock(); @@ -1690,7 +1690,7 @@ static int sceNetAdhocPdpSend(int id, const char *mac, u32 port, void *data, int struct sockaddr_in target {}; target.sin_family = AF_INET; target.sin_addr.s_addr = peer.ip; - target.sin_port = htons(dport + ((isOriPort && !isPrivateIP(peer.ip)) ? 0 : portOffset)); + target.sin_port = htons(dport + peer.portOffset); int sent = sendto(pdpsocket.id, (const char*)data, len, MSG_NOSIGNAL, (struct sockaddr*)&target, sizeof(target)); int error = errno; @@ -3665,11 +3665,11 @@ int NetAdhocPtp_Connect(int id, int timeout, int flag, bool allowForcedConnect) // sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_port = htons(ptpsocket.pport + portOffset); + u16 finalPortOffset; // Grab Peer IP - if (resolveMAC(&ptpsocket.paddr, (uint32_t*)&sin.sin_addr.s_addr)) { + if (resolveMAC(&ptpsocket.paddr, (uint32_t*)&sin.sin_addr.s_addr, &finalPortOffset)) { // Some games (ie. PSP2) might try to talk to it's self, not sure if they talked through WAN or LAN when using public Adhoc Server tho - uint16_t finalPortOffset = ((isOriPort && !isPrivateIP(sin.sin_addr.s_addr)) ? 0 : portOffset); sin.sin_port = htons(ptpsocket.pport + finalPortOffset); // Connect Socket to Peer