sceNetAdhoc, adhocctl: Check arguments like the PSP

From the net/adhoc pspautotests (pdp, ptp, poll, limits, adhocctl,
gamemode), recorded on PSPs:

- PDP and PTP: NULL pointers and nonzero flags give INVALID_ARG, before
  the socket ID is checked. Zero and multicast addresses give
  INVALID_ADDR, ports 0 and 65535 INVALID_PORT, and send lengths over
  65523 or NULL data INVALID_DATALEN. A length of 0 sends nothing and
  succeeds. Zero buffer sizes, retransmit settings and backlogs are
  accepted. PdpRecv takes a NULL sender address or port. Running out of
  socket IDs gives SOCKET_ID_NOT_AVAIL, and out-of-range IDs on
  delete/close INVALID_SOCKET_ID. PollSocket rejects flags other than
  NONBLOCK.
- adhocctl: Init checks its stack size, priority and ad hoc ID;
  AddHandler needs Init, allows the same function twice and takes at most
  4 handlers; DelHandler on an unknown ID gives ID_NOT_FOUND; bad group
  names give adhocctl's INVALID_ARG; GetParameter and GetPeerList fail
  outside a group.
- Game mode: a NULL group name and a bad minimum are rejected,
  GetGameModeInfo fails outside game mode, and the entry timeout reports
  adhocctl's TIMEOUT.

The DBZ Shin Budokai 2 workaround that replaces the game's local MAC with
ours stays, so another console's MAC is still accepted when creating a
socket.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-10-28 09:52:22 +01:00
1 parent be9c244938
commit 58d73cbbc6
3 files changed
+187 -28

No files matched your search

+2 -1
View File
@@ -1570,7 +1570,8 @@ int friendFinder() {
// Calculate EnterGameMode Timeout to prevent waiting forever for disconnected players
if (isAdhocctlBusy && adhocctlState == ADHOCCTL_STATE_DISCONNECTED && adhocctlCurrentMode == ADHOCCTL_MODE_GAMEMODE && netAdhocGameModeEntered && static_cast<s64>(now - adhocctlStartTime) > netAdhocEnterGameModeTimeout) {
netAdhocGameModeEntered = false;
notifyAdhocctlHandlers(ADHOCCTL_EVENT_ERROR, SCE_NET_ADHOC_ERROR_TIMEOUT);
// adhocctl's own TIMEOUT (pspautotests net/adhoc/gamemode).
notifyAdhocctlHandlers(ADHOCCTL_EVENT_ERROR, SCE_NET_ADHOCCTL_ERROR_TIMEOUT);
}
auto friend_finder_wait = [] {
+1 -1
View File
@@ -525,7 +525,7 @@ typedef struct SceNetAdhocMatchingContext {
// End of psp definitions
const size_t MAX_ADHOCCTL_HANDLERS = 32; //4
const size_t MAX_ADHOCCTL_HANDLERS = 4; // pspautotests net/adhoc/adhocctl
const size_t MAX_MATCHING_HANDLERS = 32; //4
enum {
+184 -26
View File
@@ -2125,6 +2125,19 @@ int sceNetAdhocctlInit(MIPSState *mips, int stackSize, int prio, u32 productAddr
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_ALREADY_INITIALIZED);
}
// pspautotests net/adhoc/adhocctl. The priority error comes from creating the library's thread,
// which the firmware does as a kernel caller (threads/threads/kernel/priority).
if (stackSize < 0xC00) {
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_STACKSIZE_TOO_SHORT, "stack too small");
}
if (prio < 0x01 || prio > 0x7E) {
return hleLogError(Log::sceNet, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "bad priority");
}
const auto adhocId = PSPPointer<SceNetAdhocctlAdhocId>::Create(productAddr);
if (!adhocId.IsValid() || adhocId->type < 0 || adhocId->type > 2) {
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_INVALID_ARG, "bad adhoc id");
}
if (g_Config.bEnableWlan) {
// Needed for peers and ad hoc servers on the same LAN (Android 17+).
System_RequestLocalNetworkPermission();
@@ -2224,6 +2237,16 @@ static int pdp_create_postoffice(const SceNetEtherAddr *saddr, int sport, int bu
return i + 1;
}
// Out of socket IDs is its own error (pspautotests net/adhoc/limits).
static bool HasFreeAdhocSocketSlot() {
for (int i = 0; i < MAX_SOCKET; i++) {
if (adhocSockets[i] == NULL) {
return true;
}
}
return false;
}
int NetAdhocPdpCreate(const char *mac, int port, int bufferSize, u32 flag, bool postoffice_enet_pdp_reliable) {
if (!g_Config.bEnableWlan) {
return -1;
@@ -2237,11 +2260,31 @@ int NetAdhocPdpCreate(const char *mac, int port, int bufferSize, u32 flag, bool
return SCE_NET_ADHOC_ERROR_NOT_INITIALIZED;
}
if (mac == NULL || bufferSize <= 0) {
// Checked in this order on the PSP (pspautotests net/adhoc/pdp). Any buffer size is accepted.
if (mac == NULL || flag != 0) {
DEBUG_LOG(Log::sceNet, "%s: bad arg", __func__);
return SCE_NET_ADHOC_ERROR_INVALID_ARG;
}
const SceNetEtherAddr *requestedMac = (const SceNetEtherAddr *)mac;
if (adhocctlCurrentMode == ADHOCCTL_MODE_NONE || isZeroMAC(requestedMac) || (requestedMac->data[0] & 1) != 0) {
DEBUG_LOG(Log::sceNet, "%s: invalid mac address supplied", __func__);
return SCE_NET_ADHOC_ERROR_INVALID_ADDR;
}
if (port == 0xFFFF) {
return SCE_NET_ADHOC_ERROR_INVALID_PORT;
}
// What the PSP does with a size under 1 isn't known; give the host one datagram's worth.
if (bufferSize <= 0) {
bufferSize = PSP_ADHOC_PDP_MFS;
}
if (!HasFreeAdhocSocketSlot()) {
return SCE_NET_ADHOC_ERROR_SOCKET_ID_NOT_AVAIL;
}
if (isPDPPortInUse(port)) {
// FIXME: When PORT_IN_USE error occured it seems the index to the socket id also increased, which means it tries to create & bind the socket first and then closes it due to failed to bind
DEBUG_LOG(Log::sceNet, "%s: port in-use", __func__);
@@ -2428,6 +2471,11 @@ static int sceNetAdhocctlGetParameter(u32 paramAddr) {
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_NOT_INITIALIZED);
}
// Only in a group (pspautotests net/adhoc/adhocctl).
if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED) {
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_DISCONNECTED, "not in a group");
}
auto ptr = PSPPointer<SceNetAdhocctlParameter>::Create(paramAddr);
if (!ptr.IsValid())
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_INVALID_ARG);
@@ -2460,6 +2508,28 @@ int sceNetAdhocPdpSend(MIPSState *mips, int id, const char *mac, u32 port, void
SceNetEtherAddr * daddr = (SceNetEtherAddr *)mac;
uint16_t dport = (uint16_t)port;
// Checked in this order on the PSP (pspautotests net/adhoc/pdp).
if (daddr == NULL || (flag & ~ADHOC_F_NONBLOCK) != 0) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_ARG, "invalid arg");
}
if (!netAdhocInited) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_NOT_INITIALIZED, "not initialized");
}
if (id <= 0 || id > MAX_SOCKET || adhocSockets[id - 1] == NULL) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_SOCKET_ID, "invalid socket id");
}
// Broadcast is the only multicast address allowed.
if (isZeroMAC(daddr) || ((daddr->data[0] & 1) != 0 && !isBroadcastMAC(daddr))) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_ADDR, "invalid address");
}
if (dport == 0 || dport == 0xFFFF) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_PORT, "invalid port");
}
// NULL data is only accepted with a length of 0.
if (len < 0 || len > PSP_ADHOC_PDP_MTU || (data == NULL && len != 0)) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_DATALEN, "invalid data length");
}
//if (dport < 7) dport += 1341;
// Really should flatten this with early outs, all this indentation is making me dizzy.
@@ -2478,7 +2548,7 @@ int sceNetAdhocPdpSend(MIPSState *mips, int id, const char *mac, u32 port, void
socket->nonblocking = flag;
// Valid Data Buffer
if (data != NULL) {
if (data != NULL || len == 0) {
// Valid Destination Address
if (daddr != NULL && !isZeroMAC(daddr)) {
// Log Destination
@@ -2712,6 +2782,29 @@ int sceNetAdhocPdpRecv(MIPSState *mips, int id, void *addr, void * port, void *b
SceNetEtherAddr *saddr = (SceNetEtherAddr *)addr;
uint16_t * sport = (uint16_t *)port; //Looking at Quake3 sourcecode (net_adhoc.c) this is an "int" (32bit) but changing here to 32bit will cause FF-Type0 to see duplicated Host (thinking it was from a different host)
int * len = (int *)dataLength;
// Checked in this order on the PSP (pspautotests net/adhoc/pdp).
if (buf == NULL || len == NULL || (flag & ~ADHOC_F_NONBLOCK) != 0) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_ARG, "invalid arg");
}
if (!netAdhocInited) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_NOT_INITIALIZED, "not initialized");
}
if (id <= 0 || id > MAX_SOCKET || adhocSockets[id - 1] == NULL) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_SOCKET_ID, "invalid socket id");
}
// The sender's address and port are optional. A blocking receive writes them later, so these
// can't be locals.
static SceNetEtherAddr discardedMac;
static uint16_t discardedPort;
if (saddr == NULL) {
saddr = &discardedMac;
}
if (sport == NULL) {
sport = &discardedPort;
port = sport;
}
if (netAdhocInited) {
// Valid Socket ID
if (id > 0 && id <= MAX_SOCKET && adhocSockets[id - 1] != NULL) {
@@ -3152,6 +3245,10 @@ int PollAdhocSocket(SceNetAdhocPollSd* sds, int count, int timeout, int nonblock
int sceNetAdhocPollSocket(MIPSState *mips, u32 socketStructAddr, int count, int timeout, int nonblock) { // timeout in microseconds
DEBUG_LOG_REPORT_ONCE(sceNetAdhocPollSocket, Log::sceNet, "UNTESTED sceNetAdhocPollSocket(%08x, %i, %i, %i) at %08x", socketStructAddr, count, timeout, nonblock, mips->pc);
// pspautotests net/adhoc/poll
if ((nonblock & ~ADHOC_F_NONBLOCK) != 0) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_ARG, "invalid flag");
}
// Library is initialized
if (netAdhocInited)
{
@@ -3272,8 +3369,8 @@ int NetAdhocPdp_Delete(int id, int unknown) {
return SCE_NET_ADHOC_ERROR_INVALID_SOCKET_ID;
}
// Invalid Argument
return SCE_NET_ADHOC_ERROR_INVALID_ARG;
// Out of range (pspautotests net/adhoc/pdp)
return SCE_NET_ADHOC_ERROR_INVALID_SOCKET_ID;
}
// Library is uninitialized
@@ -3289,6 +3386,10 @@ int NetAdhocPdp_Delete(int id, int unknown) {
static int sceNetAdhocPdpDelete(MIPSState *mips, int id, int unknown) {
// WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup right?
INFO_LOG(Log::sceNet, "sceNetAdhocPdpDelete(%d, %d) at %08x", id, unknown, mips->pc);
// The flag must be 0, checked first (pspautotests net/adhoc/pdp).
if (unknown != 0) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_ARG, "invalid flag");
}
/*
if (!g_Config.bEnableWlan) {
return 0;
@@ -3476,7 +3577,12 @@ int sceNetAdhocctlGetScanInfo(MIPSState *mips, u32 sizeAddr, u32 bufAddr) {
// TODO: Should we allow the same handler to be added more than once?
// FIXME: Do all Adhocctl HLE returning 0 and expecting error code through callback handler if there were error, instead of returning error code through the HLE ?
static u32 sceNetAdhocctlAddHandler(u32 handlerPtr, u32 handlerArg) {
bool foundHandler = false;
if (!netAdhocctlInited) {
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_NOT_INITIALIZED, "adhocctl not initialized");
}
// The same function can be added more than once, and gets a new ID each time (pspautotests
// net/adhoc/adhocctl).
u32 retval = 0;
AdhocctlHandler handler;
memset(&handler, 0, sizeof(handler));
@@ -3487,14 +3593,7 @@ static u32 sceNetAdhocctlAddHandler(u32 handlerPtr, u32 handlerArg) {
handler.entryPoint = handlerPtr;
handler.argument = handlerArg;
for (auto it = adhocctlHandlers.begin(); it != adhocctlHandlers.end(); ++it) {
if (it->second.entryPoint == handlerPtr) {
foundHandler = true;
break;
}
}
if (!foundHandler && Memory::IsValidAddress(handlerPtr)) {
if (Memory::IsValidAddress(handlerPtr)) {
if (adhocctlHandlers.size() >= MAX_ADHOCCTL_HANDLERS) {
ERROR_LOG(Log::sceNet, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): Too many handlers", handlerPtr, handlerArg);
retval = SCE_NET_ADHOCCTL_ERROR_TOO_MANY_HANDLERS;
@@ -3502,9 +3601,6 @@ static u32 sceNetAdhocctlAddHandler(u32 handlerPtr, u32 handlerArg) {
}
adhocctlHandlers[retval] = handler;
INFO_LOG(Log::sceNet, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): added handler %d", handlerPtr, handlerArg, retval);
} else if(foundHandler) {
ERROR_LOG(Log::sceNet, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): Same handler already exists", handlerPtr, handlerArg);
retval = 0; //Faking success
} else {
ERROR_LOG(Log::sceNet, "UNTESTED sceNetAdhocctlAddHandler(%x, %x): Invalid handler", handlerPtr, handlerArg);
retval = SCE_NET_ADHOCCTL_ERROR_INVALID_ARG;
@@ -3615,7 +3711,7 @@ static u32 sceNetAdhocctlDelHandler(u32 handlerID) {
adhocctlHandlers.erase(handlerID);
return hleLogInfo(Log::sceNet, 0);
} else {
return hleLogWarning(Log::sceNet, 0, "Invalid Handler ID");
return hleLogWarning(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_ID_NOT_FOUND, "Invalid Handler ID");
}
}
@@ -3872,7 +3968,7 @@ int NetAdhocctl_Create(const char *groupName) {
}
// Invalid Argument
return SCE_NET_ADHOC_ERROR_INVALID_ARG;
return SCE_NET_ADHOCCTL_ERROR_INVALID_ARG;
}
// Library uninitialized
return SCE_NET_ADHOCCTL_ERROR_NOT_INITIALIZED;
@@ -3949,7 +4045,7 @@ int NetAdhocctl_CreateEnterGameMode(const char* group_name, int game_type, int n
if (!netAdhocctlInited)
return SCE_NET_ADHOCCTL_ERROR_NOT_INITIALIZED;
if (!Memory::IsValidAddress(membersAddr))
if (group_name == NULL || !Memory::IsValidAddress(membersAddr))
return SCE_NET_ADHOCCTL_ERROR_INVALID_ARG;
if (game_type < ADHOCCTL_GAMETYPE_1A || game_type > ADHOCCTL_GAMETYPE_2A || num_members < 2 || num_members > 16 || (game_type == ADHOCCTL_GAMETYPE_1A && num_members > 4))
@@ -4025,7 +4121,7 @@ static int sceNetAdhocctlJoinEnterGameMode(MIPSState *mips, const char * group_n
if (!netAdhocctlInited)
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_NOT_INITIALIZED, "not initialized");
if (!hostMac)
if (!group_name || !hostMac)
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_INVALID_ARG, "invalid arg");
deleteAllGMB();
@@ -4063,7 +4159,10 @@ int sceNetAdhocctlCreateEnterGameModeMin(MIPSState *mips, const char *group_name
if (group_name)
memcpy(grpName, group_name, ADHOCCTL_GROUPNAME_LEN); // For logging purpose, must not be truncated
WARN_LOG_REPORT_ONCE(sceNetAdhocctlCreateEnterGameModeMin, Log::sceNet, "UNTESTED sceNetAdhocctlCreateEnterGameModeMin(%s, %i, %i, %i, %08x, %d, %i) at %08x", grpName, game_type, min_members, num_members, membersAddr, timeout, flag, mips->pc);
// We don't really need the Minimum User Check
// The minimum isn't enforced while waiting, but it is checked (pspautotests net/adhoc/gamemode).
if (min_members < 2 || min_members > num_members) {
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_INVALID_ARG, "bad minimum");
}
return hleLogDebug(Log::sceNet, NetAdhocctl_CreateEnterGameMode(group_name, game_type, num_members, membersAddr, timeout, flag));
}
@@ -4519,6 +4618,25 @@ static int sceNetAdhocPtpOpen(MIPSState *mips, const char *srcmac, int sport, co
SceNetEtherAddr* saddr = (SceNetEtherAddr*)srcmac;
SceNetEtherAddr* daddr = (SceNetEtherAddr*)dstmac;
bool isClient = false;
// pspautotests net/adhoc/ptp. Zero sizes and retransmit settings are accepted.
if (saddr == NULL || daddr == NULL || flag != 0) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_ARG, "invalid arg");
}
if (netAdhocInited && (isZeroMAC(saddr) || (saddr->data[0] & 1) != 0 || isZeroMAC(daddr))) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_ADDR, "invalid address");
}
if (netAdhocInited && (dport == 0 || dport == 0xFFFF)) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_PORT, "invalid port");
}
// What the PSP does with a buffer size under 1 isn't known; give the host one segment's worth.
if (bufsize <= 0) {
bufsize = PSP_ADHOC_PTP_MSS;
}
if (netAdhocInited && !HasFreeAdhocSocketSlot()) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_SOCKET_ID_NOT_AVAIL, "out of socket IDs");
}
// Library is initialized
if (netAdhocInited) {
// Some games (ie. DBZ Shin Budokai 2) might be getting the saddr/srcmac content from SaveState and causing problems if current MAC is different :( So we try to fix it here
@@ -4541,7 +4659,7 @@ static int sceNetAdhocPtpOpen(MIPSState *mips, const char *srcmac, int sport, co
}
// Valid Arguments
if (bufsize > 0 && rexmt_int > 0 && rexmt_cnt > 0) {
if (bufsize > 0 && rexmt_int >= 0 && rexmt_cnt >= 0) {
if (serverHasRelay)
return ptp_open_postoffice(saddr, sport, daddr, dport, bufsize);
@@ -5120,8 +5238,8 @@ int NetAdhocPtp_Close(int id, int unknown) {
return SCE_NET_ADHOC_ERROR_INVALID_SOCKET_ID;
}
// Invalid Argument
return SCE_NET_ADHOC_ERROR_INVALID_ARG;
// Out of range (pspautotests net/adhoc/ptp)
return SCE_NET_ADHOC_ERROR_INVALID_SOCKET_ID;
}
// Library is uninitialized
@@ -5136,6 +5254,10 @@ int NetAdhocPtp_Close(int id, int unknown) {
*/
static int sceNetAdhocPtpClose(MIPSState *mips, int id, int unknown) {
INFO_LOG(Log::sceNet,"sceNetAdhocPtpClose(%d,%d) at %08x",id,unknown,mips->pc);
// The flag must be 0 (pspautotests net/adhoc/ptp).
if (unknown != 0) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_ARG, "invalid flag");
}
/*if (!g_Config.bEnableWlan) {
return hleLogError(Log::sceNet, -1, "WLAN off");
}*/
@@ -5209,6 +5331,22 @@ static int sceNetAdhocPtpListen(MIPSState *mips, const char *srcmac, int sport,
// Library is initialized
SceNetEtherAddr * saddr = (SceNetEtherAddr *)srcmac;
bool isClient = false;
// pspautotests net/adhoc/ptp. Zero sizes, retransmit settings and backlog are accepted.
if (saddr == NULL || flag != 0) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_ARG, "invalid arg");
}
if (netAdhocInited && (isZeroMAC(saddr) || (saddr->data[0] & 1) != 0)) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_ADDR, "invalid address");
}
// What the PSP does with a buffer size under 1 isn't known; give the host one segment's worth.
if (bufsize <= 0) {
bufsize = PSP_ADHOC_PTP_MSS;
}
if (netAdhocInited && !HasFreeAdhocSocketSlot()) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_SOCKET_ID_NOT_AVAIL, "out of socket IDs");
}
if (netAdhocInited) {
// Some games (ie. DBZ Shin Budokai 2) might be getting the saddr/srcmac content from SaveState and causing problems :( So we try to fix it here
if (saddr != NULL) {
@@ -5230,7 +5368,7 @@ static int sceNetAdhocPtpListen(MIPSState *mips, const char *srcmac, int sport,
}
// Valid Arguments
if (bufsize > 0 && rexmt_int > 0 && rexmt_cnt > 0 && backlog > 0)
if (bufsize > 0 && rexmt_int >= 0 && rexmt_cnt >= 0 && backlog >= 0)
{
if (serverHasRelay)
return ptp_listen_postoffice(saddr, sport, bufsize);
@@ -5392,6 +5530,9 @@ static int sceNetAdhocPtpSend(MIPSState *mips, int id, u32 dataAddr, u32 dataSiz
int * len = dataSizeAddr ? (int *)Memory::GetPointerOrException(dataSizeAddr) : nullptr;
const char * data = Memory::GetCharPointer(dataAddr);
if (len == NULL) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_ARG, "invalid arg");
}
// Library is initialized
if (netAdhocInited) {
// Valid Socket
@@ -5403,6 +5544,13 @@ static int sceNetAdhocPtpSend(MIPSState *mips, int id, u32 dataAddr, u32 dataSiz
// Connected Socket
if (ptpsocket.state == ADHOC_PTP_STATE_ESTABLISHED || ptpsocket.state == ADHOC_PTP_STATE_SYN_SENT) {
// A length of 0 sends nothing; NULL data is a length error (pspautotests net/adhoc/ptp).
if (*len == 0) {
return hleLogDebug(Log::sceNet, 0, "nothing to send");
}
if (*len < 0 || data == NULL) {
return hleLogError(Log::sceNet, SCE_NET_ADHOC_ERROR_INVALID_DATALEN, "invalid data length");
}
// Valid Arguments
if (data != NULL && len != NULL && *len > 0) {
// Schedule Timeout Removal
@@ -6122,6 +6270,10 @@ static int sceNetAdhocctlGetGameModeInfo(u32 infoAddr) {
if (!Memory::IsValidAddress(infoAddr))
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_INVALID_ARG, "invalid arg");
// pspautotests net/adhoc/gamemode
if (!netAdhocGameModeEntered)
return hleLogError(Log::sceNet, SCE_NET_ADHOCCTL_ERROR_NOT_ENTER_GAMEMODE, "not in game mode");
SceNetAdhocctlGameModeInfo* gmInfo = (SceNetAdhocctlGameModeInfo*)Memory::GetPointerOrException(infoAddr);
// Writes number of participants and each participating MAC address into infoAddr/gmInfo
gmInfo->num = static_cast<s32_le>(gameModeMacs.size());
@@ -6154,9 +6306,15 @@ static int sceNetAdhocctlGetPeerList(MIPSState *mips, u32 sizeAddr, u32 bufAddr)
// Initialized Library
if (netAdhocctlInited) {
// Outside a group, an error from the auth library (pspautotests net/adhoc/adhocctl).
if (adhocctlState == ADHOCCTL_STATE_DISCONNECTED) {
if (buflen != NULL) {
*buflen = 0;
}
return hleLogError(Log::sceNet, 0x80410682, "not in a group");
}
// Minimum Arguments
if (buflen != NULL) {
// FIXME: Sometimes returing 0x80410682 when Adhocctl is still BUSY or before AdhocctlGetState became ADHOCCTL_STATE_CONNECTED or related to Auth/Library ?
// Multithreading Lock
peerlock.lock();