Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AdhocMatching fix - Gran Turismo #13375

Merged
merged 9 commits into from
Sep 3, 2020
4 changes: 4 additions & 0 deletions Core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,10 @@ std::string CreateRandMAC() {
srand(time(nullptr));
for (int i = 0; i < 6; i++) {
u32 value = rand() % 256;
if (i == 0) {
// Making sure the 1st 2-bits on the 1st byte of OUI are zero to prevent issue with some games (ie. Gran Turismo)
value &= 0xfc;
}
if (value <= 15)
randStream << '0' << std::hex << value;
else
Expand Down
98 changes: 64 additions & 34 deletions Core/HLE/proAdhoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,16 @@ SockAddrIN4 g_localhostIP;
sockaddr LocalIP;
int defaultWlanChannel = PSP_SYSTEMPARAM_ADHOC_CHANNEL_1; // Don't put 0(Auto) here, it needed to be a valid/actual channel number

bool isMacMatch(const SceNetEtherAddr* addr1, const SceNetEtherAddr* addr2) {
// Ignoring the 1st byte since there are games (ie. Gran Turismo) who tamper with the 1st byte of OUI to change the unicast/multicast bit
return (memcmp(((const char*)addr1)+1, ((const char*)addr2)+1, ETHER_ADDR_LEN-1) == 0);
}

bool isLocalMAC(const SceNetEtherAddr * addr) {
SceNetEtherAddr saddr;
getLocalMac(&saddr);

return (memcmp((const void*)addr, (const void*)&saddr, ETHER_ADDR_LEN) == 0);
return isMacMatch(addr, &saddr);
}

bool isPDPPortInUse(uint16_t port) {
Expand Down Expand Up @@ -123,6 +128,8 @@ SceNetAdhocMatchingMemberInternal* addMember(SceNetAdhocMatchingContext * contex
// Already existed
if (peer != NULL) {
WARN_LOG(SCENET, "Member Peer Already Existed! Updating [%s]", mac2str(mac).c_str());
peer->state = 0;
peer->sending = 0;
peer->lastping = CoreTiming::GetGlobalTimeUsScaled();
}
// Member is not added yet
Expand All @@ -132,8 +139,10 @@ SceNetAdhocMatchingMemberInternal* addMember(SceNetAdhocMatchingContext * contex
memset(peer, 0, sizeof(SceNetAdhocMatchingMemberInternal));
peer->mac = *mac;
peer->lastping = CoreTiming::GetGlobalTimeUsScaled();
peerlock.lock();
peer->next = context->peerlist;
context->peerlist = peer;
peerlock.unlock();
}
}
return peer;
Expand Down Expand Up @@ -193,7 +202,7 @@ SceNetAdhocctlPeerInfo * findFriend(SceNetEtherAddr * MAC) {

// Iterate Friends
for (; peer != NULL; peer = peer->next) {
if (IsMatch(peer->mac_addr, *MAC)) break;
if (isMacMatch(&peer->mac_addr, MAC)) break;
}

// Return found friend
Expand Down Expand Up @@ -262,7 +271,7 @@ SceNetAdhocctlScanInfo * findGroup(SceNetEtherAddr * MAC) {

// Iterate Groups
for (; group != NULL; group = group->next) {
if (IsMatch(group->bssid.mac_addr, *MAC)) break;
if (isMacMatch(&group->bssid.mac_addr, MAC)) break;
}

// Return found group
Expand Down Expand Up @@ -432,7 +441,7 @@ void postAcceptCleanPeerList(SceNetAdhocMatchingContext * context)
SceNetAdhocMatchingMemberInternal * next = peer->next;

// Unneeded Peer
if (peer->state != PSP_ADHOC_MATCHING_PEER_CHILD && peer->state != PSP_ADHOC_MATCHING_PEER_P2P && peer->state != PSP_ADHOC_MATCHING_PEER_PARENT) {
if (peer->state != PSP_ADHOC_MATCHING_PEER_CHILD && peer->state != PSP_ADHOC_MATCHING_PEER_P2P && peer->state != PSP_ADHOC_MATCHING_PEER_PARENT && peer->state != 0) {
deletePeer(context, peer);
delcount++;
}
Expand All @@ -445,7 +454,7 @@ void postAcceptCleanPeerList(SceNetAdhocMatchingContext * context)
// Free Peer Lock
peerlock.unlock();

INFO_LOG(SCENET, "Removing Unneeded Peer (%i/%i)", delcount, peercount);
INFO_LOG(SCENET, "Removing Unneeded Peers (%i/%i)", delcount, peercount);
}

/**
Expand All @@ -461,39 +470,52 @@ void postAcceptAddSiblings(SceNetAdhocMatchingContext * context, int siblingcoun
// As the buffer of "siblings" isn't properly aligned I don't want to risk a crash.
uint8_t * siblings_u8 = (uint8_t *)siblings;

// Iterate Siblings
for (int i = 0; i < siblingcount; i++)
peerlock.lock();
// Iterate Siblings. Reversed so these siblings are added into peerlist in the same order with the peerlist on host/parent side
for (int i = siblingcount - 1; i >= 0 ; i--)
{
// Allocate Memory
SceNetAdhocMatchingMemberInternal * sibling = (SceNetAdhocMatchingMemberInternal *)malloc(sizeof(SceNetAdhocMatchingMemberInternal));
SceNetEtherAddr* mac = (SceNetEtherAddr*)(siblings_u8 + sizeof(SceNetEtherAddr) * i);

// Allocated Memory
if (sibling != NULL)
{
// Clear Memory
memset(sibling, 0, sizeof(SceNetAdhocMatchingMemberInternal));
auto peer = findPeer(context, mac);
// Already exist
if (peer != NULL) {
// Set Peer State
peer->state = PSP_ADHOC_MATCHING_PEER_CHILD;
peer->sending = 0;
peer->lastping = CoreTiming::GetGlobalTimeUsScaled();
WARN_LOG(SCENET, "Updating Sibling Peer %s", mac2str(mac).c_str());
}
else {
// Allocate Memory
SceNetAdhocMatchingMemberInternal* sibling = (SceNetAdhocMatchingMemberInternal*)malloc(sizeof(SceNetAdhocMatchingMemberInternal));

// Save MAC Address
memcpy(&sibling->mac, siblings_u8 + sizeof(SceNetEtherAddr) * i, sizeof(SceNetEtherAddr));
// Allocated Memory
if (sibling != NULL)
{
// Clear Memory
memset(sibling, 0, sizeof(SceNetAdhocMatchingMemberInternal));

// Set Peer State
sibling->state = PSP_ADHOC_MATCHING_PEER_CHILD;
// Save MAC Address
memcpy(&sibling->mac, mac, sizeof(SceNetEtherAddr));

// Initialize Ping Timer
sibling->lastping = CoreTiming::GetGlobalTimeUsScaled(); //real_time_now()*1000000.0;
// Set Peer State
sibling->state = PSP_ADHOC_MATCHING_PEER_CHILD;

peerlock.lock();
// Link Peer, should check whether it's already added before
sibling->next = context->peerlist;
context->peerlist = sibling;
peerlock.unlock();
// Initialize Ping Timer
sibling->lastping = CoreTiming::GetGlobalTimeUsScaled(); //real_time_now()*1000000.0;

// Spawn Established Event. FIXME: ESTABLISHED event should only be triggered for Parent/P2P peer?
//spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_ESTABLISHED, &sibling->mac, 0, NULL);
// Link Peer
sibling->next = context->peerlist;
context->peerlist = sibling;

INFO_LOG(SCENET, "Accepting Peer %s", mac2str(&sibling->mac).c_str());
// Spawn Established Event. FIXME: ESTABLISHED event should only be triggered for Parent/P2P peer?
//spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_ESTABLISHED, &sibling->mac, 0, NULL);

INFO_LOG(SCENET, "Accepting Sibling Peer %s", mac2str(&sibling->mac).c_str());
}
}
}
peerlock.unlock();
}

/**
Expand Down Expand Up @@ -533,7 +555,7 @@ SceNetAdhocMatchingMemberInternal * findPeer(SceNetAdhocMatchingContext * contex
for (; peer != NULL; peer = peer->next)
{
// Found Peer in List
if (memcmp(&peer->mac, mac, sizeof(SceNetEtherAddr)) == 0)
if (isMacMatch(&peer->mac, mac))
{
// Return Peer Pointer
return peer;
Expand Down Expand Up @@ -883,13 +905,14 @@ void handleTimeout(SceNetAdhocMatchingContext * context)

u64_le now = CoreTiming::GetGlobalTimeUsScaled(); //real_time_now()*1000000.0
// Timeout!, may be we shouldn't kick timedout members ourself and let the game do it
if ((now - peer->lastping) >= context->timeout)
if (peer->state != 0 && (now - peer->lastping) >= context->timeout)
{
// Spawn Timeout Event
if ((context->mode == PSP_ADHOC_MATCHING_MODE_CHILD && (peer->state == PSP_ADHOC_MATCHING_PEER_CHILD || peer->state == PSP_ADHOC_MATCHING_PEER_PARENT)) ||
if ((context->mode == PSP_ADHOC_MATCHING_MODE_CHILD && (/*peer->state == PSP_ADHOC_MATCHING_PEER_CHILD ||*/ peer->state == PSP_ADHOC_MATCHING_PEER_PARENT)) ||
(context->mode == PSP_ADHOC_MATCHING_MODE_PARENT && peer->state == PSP_ADHOC_MATCHING_PEER_CHILD) ||
(context->mode == PSP_ADHOC_MATCHING_MODE_P2P && peer->state == PSP_ADHOC_MATCHING_PEER_P2P)) {
spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_TIMEOUT, &peer->mac, 0, NULL); // This is the only code that use PSP_ADHOC_MATCHING_EVENT_TIMEOUT, should we let it timedout?
// FIXME: TIMEOUT event should only be triggered on Parent/P2P mode and for Parent/P2P peer?
spawnLocalEvent(context, PSP_ADHOC_MATCHING_EVENT_TIMEOUT, &peer->mac, 0, NULL);
}

INFO_LOG(SCENET, "TimedOut Member Peer %s (%lldms)", mac2str(&peer->mac).c_str(), (context->timeout/1000));
Expand Down Expand Up @@ -1663,10 +1686,13 @@ void getLocalMac(SceNetEtherAddr * addr){
uint8_t mac[ETHER_ADDR_LEN] = {0};
if (PPSSPP_ID > 1) {
memset(&mac, PPSSPP_ID, sizeof(mac));
// Making sure the 1st 2-bits on the 1st byte of OUI are zero to prevent issue with some games (ie. Gran Turismo)
mac[0] &= 0xfc;
}
else
if (!ParseMacAddress(g_Config.sMACAddress.c_str(), mac)) {
ERROR_LOG(SCENET, "Error parsing mac address %s", g_Config.sMACAddress.c_str());
memset(&mac, 0, sizeof(mac));
}
memcpy(addr, mac, ETHER_ADDR_LEN);
}
Expand Down Expand Up @@ -1911,6 +1937,10 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){
}
}

bool isZeroMAC(const SceNetEtherAddr* addr) {
return (memcmp(addr->data, "\x00\x00\x00\x00\x00\x00", ETHER_ADDR_LEN) == 0);
}

bool isBroadcastMAC(const SceNetEtherAddr * addr) {
return (memcmp(addr->data, "\xFF\xFF\xFF\xFF\xFF\xFF", ETHER_ADDR_LEN) == 0);
}
Expand Down Expand Up @@ -1958,7 +1988,7 @@ bool resolveMAC(SceNetEtherAddr * mac, uint32_t * ip) {
SceNetEtherAddr localMac;
getLocalMac(&localMac);
// Local MAC Requested
if (memcmp(&localMac, mac, sizeof(SceNetEtherAddr)) == 0) {
if (isMacMatch(&localMac, mac)) {
// Get Local IP Address
sockaddr_in sockAddr;
getLocalIp(&sockAddr);
Expand All @@ -1975,7 +2005,7 @@ bool resolveMAC(SceNetEtherAddr * mac, uint32_t * ip) {
// Iterate Peers
for (; peer != NULL; peer = peer->next) {
// Found Matching Peer
if (memcmp(&peer->mac_addr, mac, sizeof(SceNetEtherAddr)) == 0) {
if (isMacMatch(&peer->mac_addr, mac)) {
// Copy Data
*ip = peer->ip_addr;

Expand Down
22 changes: 18 additions & 4 deletions Core/HLE/proAdhoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -646,10 +646,10 @@ enum {
#define PSP_ADHOC_MATCHING_EVENT_DENY 4
#define PSP_ADHOC_MATCHING_EVENT_CANCEL 5
#define PSP_ADHOC_MATCHING_EVENT_ACCEPT 6
#define PSP_ADHOC_MATCHING_EVENT_ESTABLISHED 7
#define PSP_ADHOC_MATCHING_EVENT_TIMEOUT 8
#define PSP_ADHOC_MATCHING_EVENT_ESTABLISHED 7 // Should only be triggered on Parent/P2P mode and for Parent/P2P peer ?
#define PSP_ADHOC_MATCHING_EVENT_TIMEOUT 8 // Should only be triggered on Parent/P2P mode and for Parent/P2P peer ?
#define PSP_ADHOC_MATCHING_EVENT_ERROR 9
#define PSP_ADHOC_MATCHING_EVENT_BYE 10
#define PSP_ADHOC_MATCHING_EVENT_BYE 10 // Should only be triggered on Parent/P2P mode and for Parent/P2P peer ?
#define PSP_ADHOC_MATCHING_EVENT_DATA 11
#define PSP_ADHOC_MATCHING_EVENT_DATA_ACK 12
#define PSP_ADHOC_MATCHING_EVENT_DATA_TIMEOUT 13
Expand Down Expand Up @@ -857,10 +857,17 @@ bool SetMatchingInCallback(SceNetAdhocMatchingContext* context, bool IsInCB);
int IsAdhocctlInCallback();
int SetAdhocctlInCallback(bool IsInCB);

/**
* Compare MAC Addresses
* @param addr1 & addr2 To-be-compared MAC Address
* @return True if both matched
*/
bool isMacMatch(const SceNetEtherAddr* addr1, const SceNetEtherAddr* addr2);

/**
* Local MAC Check
* @param saddr To-be-checked MAC Address
* @return 1 if valid or... 0
* @return True if it's local mac
*/
bool isLocalMAC(const SceNetEtherAddr * addr);

Expand Down Expand Up @@ -1246,6 +1253,13 @@ int getPTPSocketCount();
*/
int initNetwork(SceNetAdhocctlAdhocId *adhocid);

/**
* Zero MAC Check
* @param addr To-be-checked MAC Address
* @return true if MAC is all zeroes
*/
bool isZeroMAC(const SceNetEtherAddr* addr);

/**
* Broadcast MAC Check
* @param addr To-be-checked MAC Address
Expand Down
9 changes: 7 additions & 2 deletions Core/HLE/sceNet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,8 @@ void __NetApctlCallbacks()
}

// Must be delayed long enough whenever there is a pending callback.
hleDelayResult(0, "Prevent Apctl thread from blocking", delayus);
sceKernelDelayThread(delayus);
hleSkipDeadbeef();;
}

static inline u32 AllocUser(u32 size, bool fromTop, const char *name) {
Expand Down Expand Up @@ -609,6 +610,8 @@ static u32 sceWlanGetEtherAddr(u32 addrAddr) {
u8 *addr = Memory::GetPointer(addrAddr);
if (PPSSPP_ID > 1) {
Memory::Memset(addrAddr, PPSSPP_ID, 6);
// Making sure the 1st 2-bits on the 1st byte of OUI are zero to prevent issue with some games (ie. Gran Turismo)
addr[0] &= 0xfc;
}
else
// Read MAC Address from config
Expand Down Expand Up @@ -756,6 +759,9 @@ static int sceNetApctlInit(int stackSize, int initPriority) {
if (netApctlInited)
return ERROR_NET_APCTL_ALREADY_INITIALIZED;

apctlEvents.clear();
netApctlState = PSP_NET_APCTL_STATE_DISCONNECTED;

// Set default value before connected to an AP
memset(&netApctlInfo, 0, sizeof(netApctlInfo)); // NetApctl_InitInfo();
std::string APname = "Wifi"; // fake AP/hotspot
Expand All @@ -776,7 +782,6 @@ static int sceNetApctlInit(int stackSize, int initPriority) {
}

netApctlInited = true;
netApctlState = PSP_NET_APCTL_STATE_DISCONNECTED;

return 0;
}
Expand Down