2013-04-29 12:40:09 +09:00
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
// This is pretty much a stub implementation. Doesn't actually do anything, just tries to return values
2014-03-15 11:22:19 -07:00
// to keep games happy anyway.
2013-04-29 12:40:09 +09:00
2022-08-04 16:35:30 +07:00
# include <mutex>
# include <deque>
2020-08-12 20:28:14 +07:00
# include <StringUtils.h>
# include "Core/MemMapHelpers.h"
2022-08-04 16:35:30 +07:00
# include "Core/CoreTiming.h"
# include "Core/Config.h"
2014-03-15 11:22:19 -07:00
# include "Core/HLE/HLE.h"
# include "Core/HLE/FunctionWrappers.h"
# include "Core/HLE/sceNp.h"
2013-04-29 12:40:09 +09:00
2020-08-12 20:28:14 +07:00
bool npAuthInited = false ;
2022-02-28 16:20:03 +07:00
int npSigninState = NP_SIGNIN_STATUS_NONE ;
2020-08-12 20:28:14 +07:00
SceNpAuthMemoryStat npAuthMemStat = { } ;
2022-02-28 16:20:03 +07:00
PSPTimeval npSigninTimestamp { } ;
// TODO: These should probably be grouped in a struct, since they're used to generate an auth ticket
int npParentalControl = PARENTAL_CONTROL_ENABLED ;
int npUserAge = 24 ; // faking user Age to 24 yo
int npChatRestriction = 0 ; // default/initial value on Patapon 3 is 1 (restricted boolean?)
SceNpMyLanguages npMyLangList = { 1033 , 2057 , 1036 } ;
char npCountryCode [ 3 ] = " fr " ; // dummy data taken from https://www.psdevwiki.com/ps3/X-I-5-Ticket
char npRegionCode [ 3 ] = " c9 " ; // not sure what "c9" meant, since it was close to country code data, might be region-related data?
std : : string npOnlineId = " DummyOnlineId " ; // SceNpOnlineId struct?
std : : string npServiceId = " " ; // UNO game uses EP2006-NPEH00020_00
std : : string npAvatarUrl = " http://DummyAvatarUrl " ; // SceNpAvatarUrl struct?
SceNpCommunicationId npTitleId ;
2020-08-12 20:28:14 +07:00
std : : recursive_mutex npAuthEvtMtx ;
std : : deque < NpAuthArgs > npAuthEvents ;
std : : map < int , NpAuthHandler > npAuthHandlers ;
// Tickets data are in big-endian based on captured packets
int writeTicketParam ( u8 * buffer , const u16_be type , const char * data = nullptr , const u16_be size = 0 ) {
if ( buffer = = nullptr ) return 0 ;
u16_be sz = ( data = = nullptr ) ? static_cast < u16_be > ( 0 ) : size ;
memcpy ( buffer , & type , 2 ) ;
memcpy ( buffer + 2 , & sz , 2 ) ;
2022-02-28 16:20:03 +07:00
if ( sz > 0 & & data ! = nullptr )
memcpy ( buffer + 4 , data , sz ) ;
2020-08-12 20:28:14 +07:00
return sz + 4 ;
}
int writeTicketStringParam ( u8 * buffer , const u16_be type , const char * data = nullptr , const u16_be size = 0 ) {
if ( buffer = = nullptr ) return 0 ;
u16_be sz = ( data = = nullptr ) ? static_cast < u16_be > ( 0 ) : size ;
memcpy ( buffer , & type , 2 ) ;
memcpy ( buffer + 2 , & sz , 2 ) ;
if ( sz > 0 ) {
memset ( buffer + 4 , 0 , sz ) ;
truncate_cpy ( ( char * ) buffer + 4 , sz , data ) ;
}
return sz + 4 ;
}
int writeTicketU32Param ( u8 * buffer , const u16_be type , const u32_be data ) {
if ( buffer = = nullptr ) return 0 ;
u16_be sz = 4 ;
memcpy ( buffer , & type , 2 ) ;
memcpy ( buffer + 2 , & sz , 2 ) ;
memcpy ( buffer + 4 , & data , 4 ) ;
return sz + 4 ;
}
int writeTicketU64Param ( u8 * buffer , const u16_be type , const u64_be data ) {
if ( buffer = = nullptr ) return 0 ;
u16_be sz = 8 ;
memcpy ( buffer , & type , 2 ) ;
memcpy ( buffer + 2 , & sz , 2 ) ;
memcpy ( buffer + 4 , & data , sz ) ;
return sz + 4 ;
}
void notifyNpAuthHandlers ( u32 id , u32 result , u32 argAddr ) {
std : : lock_guard < std : : recursive_mutex > npAuthGuard ( npAuthEvtMtx ) ;
npAuthEvents . push_back ( { id , result , argAddr } ) ;
}
static int sceNpInit ( )
2013-04-29 12:40:09 +09:00
{
2022-02-28 16:20:03 +07:00
ERROR_LOG ( SCENET , " UNIMPL %s() " , __FUNCTION__ ) ;
2022-05-30 02:42:00 +07:00
npOnlineId = g_Config . sNickName ;
2013-04-29 12:40:09 +09:00
return 0 ;
}
2020-08-12 20:27:03 +07:00
static int sceNpTerm ( )
2013-04-29 12:40:09 +09:00
{
// No parameters
2022-02-28 16:20:03 +07:00
ERROR_LOG ( SCENET , " UNIMPL %s() " , __FUNCTION__ ) ;
2020-08-12 20:27:03 +07:00
return 0 ;
}
2020-08-12 20:28:14 +07:00
static int sceNpGetContentRatingFlag ( u32 parentalControlAddr , u32 userAgeAddr )
2020-08-12 20:27:03 +07:00
{
2022-02-28 16:20:03 +07:00
WARN_LOG ( SCENET , " UNTESTED %s(%08x, %08x) " , __FUNCTION__ , parentalControlAddr , userAgeAddr ) ;
2020-08-12 20:28:14 +07:00
if ( ! Memory : : IsValidAddress ( parentalControlAddr ) | | ! Memory : : IsValidAddress ( userAgeAddr ) )
2022-02-28 16:20:03 +07:00
return hleLogError ( SCENET , SCE_NP_ERROR_INVALID_ARGUMENT , " invalid arg " ) ;
INFO_LOG ( SCENET , " %s - Parental Control: %d " , __FUNCTION__ , npParentalControl ) ;
INFO_LOG ( SCENET , " %s - User Age: %d " , __FUNCTION__ , npUserAge ) ;
2020-08-12 20:28:14 +07:00
2022-02-28 16:20:03 +07:00
Memory : : Write_U32 ( npParentalControl , parentalControlAddr ) ;
Memory : : Write_U32 ( npUserAge , userAgeAddr ) ;
2020-08-12 20:28:14 +07:00
return 0 ;
}
static int sceNpGetChatRestrictionFlag ( u32 flagAddr )
{
2022-02-28 16:20:03 +07:00
WARN_LOG ( SCENET , " UNTESTED %s(%08x) " , __FUNCTION__ , flagAddr ) ;
2020-08-12 20:28:14 +07:00
if ( ! Memory : : IsValidAddress ( flagAddr ) )
2022-02-28 16:20:03 +07:00
return hleLogError ( SCENET , SCE_NP_ERROR_INVALID_ARGUMENT , " invalid arg " ) ;
INFO_LOG ( SCENET , " %s - Chat Restriction: %d " , __FUNCTION__ , npChatRestriction ) ;
Memory : : Write_U32 ( npChatRestriction , flagAddr ) ;
return 0 ;
}
static int sceNpGetOnlineId ( u32 idPtr )
{
WARN_LOG ( SCENET , " UNTESTED %s(%08x) " , __FUNCTION__ , idPtr ) ;
if ( ! Memory : : IsValidAddress ( idPtr ) )
return hleLogError ( SCENET , SCE_NP_ERROR_INVALID_ARGUMENT , " invalid arg " ) ;
SceNpOnlineId dummyOnlineId { } ;
truncate_cpy ( dummyOnlineId . data , sizeof ( dummyOnlineId . data ) , npOnlineId . c_str ( ) ) ;
INFO_LOG ( SCENET , " %s - Online ID: %s " , __FUNCTION__ , dummyOnlineId . data ) ;
Memory : : WriteStruct ( idPtr , & dummyOnlineId ) ;
return 0 ;
}
int NpGetNpId ( SceNpId * npid )
{
truncate_cpy ( npid - > handle . data , sizeof ( npid - > handle . data ) , npOnlineId . c_str ( ) ) ;
return 0 ;
}
static int sceNpGetNpId ( u32 idPtr )
{
WARN_LOG ( SCENET , " UNTESTED %s(%08x) " , __FUNCTION__ , idPtr ) ;
2020-08-12 20:28:14 +07:00
2022-02-28 16:20:03 +07:00
if ( ! Memory : : IsValidAddress ( idPtr ) )
return hleLogError ( SCENET , SCE_NP_ERROR_INVALID_ARGUMENT , " invalid arg " ) ;
SceNpId dummyNpId { } ;
int retval = NpGetNpId ( & dummyNpId ) ;
if ( retval < 0 )
return hleLogError ( SCENET , retval ) ;
INFO_LOG ( SCENET , " %s - Online ID: %s " , __FUNCTION__ , dummyNpId . handle . data ) ;
std : : string datahex ;
DataToHexString ( dummyNpId . opt , sizeof ( dummyNpId . opt ) , & datahex ) ;
INFO_LOG ( SCENET , " %s - Options?: %s " , __FUNCTION__ , datahex . c_str ( ) ) ;
Memory : : WriteStruct ( idPtr , & dummyNpId ) ;
return 0 ;
}
static int sceNpGetAccountRegion ( u32 countryCodePtr , u32 regionCodePtr )
{
WARN_LOG ( SCENET , " UNTESTED %s(%08x, %08x) " , __FUNCTION__ , countryCodePtr , regionCodePtr ) ;
if ( ! Memory : : IsValidAddress ( countryCodePtr ) | | ! Memory : : IsValidAddress ( regionCodePtr ) )
return hleLogError ( SCENET , SCE_NP_ERROR_INVALID_ARGUMENT , " invalid arg " ) ;
SceNpCountryCode dummyCountryCode { } ;
memcpy ( dummyCountryCode . data , npCountryCode , sizeof ( dummyCountryCode . data ) ) ;
SceNpCountryCode dummyRegionCode { } ;
memcpy ( dummyRegionCode . data , npRegionCode , sizeof ( dummyRegionCode . data ) ) ;
2022-08-06 03:10:59 +07:00
INFO_LOG ( SCENET , " %s - Country Code: %s " , __FUNCTION__ , dummyCountryCode . data ) ;
INFO_LOG ( SCENET , " %s - Region? Code: %s " , __FUNCTION__ , dummyRegionCode . data ) ;
2022-02-28 16:20:03 +07:00
Memory : : WriteStruct ( countryCodePtr , & dummyCountryCode ) ;
Memory : : WriteStruct ( regionCodePtr , & dummyRegionCode ) ;
return 0 ;
}
static int sceNpGetMyLanguages ( u32 langListPtr )
{
WARN_LOG ( SCENET , " UNTESTED %s(%08x) " , __FUNCTION__ , langListPtr ) ;
if ( ! Memory : : IsValidAddress ( langListPtr ) )
return hleLogError ( SCENET , SCE_NP_ERROR_INVALID_ARGUMENT , " invalid arg " ) ;
INFO_LOG ( SCENET , " %s - Language1 Code: %d " , __FUNCTION__ , npMyLangList . language1 ) ;
INFO_LOG ( SCENET , " %s - Language2 Code: %d " , __FUNCTION__ , npMyLangList . language2 ) ;
INFO_LOG ( SCENET , " %s - Language3 Code: %d " , __FUNCTION__ , npMyLangList . language3 ) ;
Memory : : WriteStruct ( langListPtr , & npMyLangList ) ;
return 0 ;
}
static int sceNpGetUserProfile ( u32 profilePtr )
{
WARN_LOG ( SCENET , " UNTESTED %s(%08x) " , __FUNCTION__ , profilePtr ) ;
if ( ! Memory : : IsValidAddress ( profilePtr ) )
return hleLogError ( SCENET , SCE_NP_ERROR_INVALID_ARGUMENT , " invalid arg " ) ;
SceNpUserInformation dummyProfile { } ;
truncate_cpy ( dummyProfile . userId . handle . data , sizeof ( dummyProfile . userId . handle . data ) , npOnlineId . c_str ( ) ) ;
truncate_cpy ( dummyProfile . icon . data , sizeof ( dummyProfile . icon . data ) , npAvatarUrl . c_str ( ) ) ;
INFO_LOG ( SCENET , " %s - Online ID: %s " , __FUNCTION__ , dummyProfile . userId . handle . data ) ;
std : : string datahex ;
DataToHexString ( dummyProfile . userId . opt , sizeof ( dummyProfile . userId . opt ) , & datahex ) ;
INFO_LOG ( SCENET , " %s - Options?: %s " , __FUNCTION__ , datahex . c_str ( ) ) ;
INFO_LOG ( SCENET , " %s - Avatar URL: %s " , __FUNCTION__ , dummyProfile . icon . data ) ;
Memory : : WriteStruct ( profilePtr , & dummyProfile ) ;
2020-08-12 20:28:14 +07:00
2013-04-29 12:40:09 +09:00
return 0 ;
}
const HLEFunction sceNp [ ] = {
2020-08-12 20:28:14 +07:00
{ 0X857B47D3 , & WrapI_V < sceNpInit > , " sceNpInit " , ' i ' , " " } ,
2020-08-12 20:27:03 +07:00
{ 0X37E1E274 , & WrapI_V < sceNpTerm > , " sceNpTerm " , ' i ' , " " } ,
2020-08-12 20:28:14 +07:00
{ 0XBB069A87 , & WrapI_UU < sceNpGetContentRatingFlag > , " sceNpGetContentRatingFlag " , ' i ' , " xx " } ,
{ 0X1D60AE4B , & WrapI_U < sceNpGetChatRestrictionFlag > , " sceNpGetChatRestrictionFlag " , ' i ' , " x " } ,
2022-02-28 16:20:03 +07:00
{ 0x4B5C71C8 , & WrapI_U < sceNpGetOnlineId > , " sceNpGetOnlineId " , ' i ' , " x " } ,
{ 0x633B5F71 , & WrapI_U < sceNpGetNpId > , " sceNpGetNpId " , ' i ' , " x " } ,
{ 0x7E0864DF , & WrapI_U < sceNpGetUserProfile > , " sceNpGetUserProfile " , ' i ' , " x " } ,
{ 0xA0BE3C4B , & WrapI_UU < sceNpGetAccountRegion > , " sceNpGetAccountRegion " , ' i ' , " xx " } ,
{ 0xCDCC21D3 , & WrapI_U < sceNpGetMyLanguages > , " sceNpGetMyLanguages " , ' i ' , " x " } ,
2013-04-29 12:40:09 +09:00
} ;
void Register_sceNp ( )
{
RegisterModule ( " sceNp " , ARRAY_SIZE ( sceNp ) , sceNp ) ;
}
2020-08-12 20:27:03 +07:00
static int sceNpAuthTerm ( )
2013-11-14 22:43:00 +08:00
{
// No parameters
2022-02-28 16:20:03 +07:00
ERROR_LOG ( SCENET , " UNIMPL %s() " , __FUNCTION__ ) ;
2020-08-12 20:28:14 +07:00
npAuthInited = false ;
2020-08-12 20:27:03 +07:00
return 0 ;
}
static int sceNpAuthInit ( u32 poolSize , u32 stackSize , u32 threadPrio )
{
2022-02-28 16:20:03 +07:00
ERROR_LOG ( SCENET , " UNIMPL %s(%d, %d, %d) " , __FUNCTION__ , poolSize , stackSize , threadPrio ) ;
npAuthMemStat . npMemSize = poolSize - 0x20 ;
npAuthMemStat . npMaxMemSize = 0x4050 ; // Dummy maximum foot print
npAuthMemStat . npFreeMemSize = npAuthMemStat . npMemSize ;
2020-09-04 01:48:15 +07:00
npAuthEvents . clear ( ) ;
2020-08-12 20:28:14 +07:00
npAuthInited = true ;
return 0 ;
}
2022-02-28 16:20:03 +07:00
int sceNpAuthGetMemoryStat ( u32 memStatAddr )
2020-08-12 20:28:14 +07:00
{
2022-02-28 16:20:03 +07:00
ERROR_LOG ( SCENET , " UNIMPL %s(%08x) " , __FUNCTION__ , memStatAddr ) ;
2020-08-12 20:28:14 +07:00
if ( ! Memory : : IsValidAddress ( memStatAddr ) )
2022-02-28 16:20:03 +07:00
return hleLogError ( SCENET , SCE_NP_AUTH_ERROR_INVALID_ARGUMENT , " invalid arg " ) ;
2020-08-12 20:28:14 +07:00
Memory : : WriteStruct ( memStatAddr , & npAuthMemStat ) ;
2013-11-14 22:43:00 +08:00
return 0 ;
}
2020-08-12 20:27:03 +07:00
/*
" Authenticating matching server usage license " on Patapon 3. Could be waiting for a state change for eternity ? probably need to trigger a callback handler ?
2020-08-12 20:28:14 +07:00
TODO : Login to " https://auth.np.ac.playstation.net/nav/auth " based on https : //www.psdevwiki.com/ps3/Online_Connections
param seems to be a struct where offset :
2020-08-12 20:27:03 +07:00
+ 00 : 32 - bit is the size of the struct ( ie . 36 bytes ) ,
2020-08-12 20:28:14 +07:00
+ 04 : 32 - bit is also a small number ( ie . 3 ) a mode / event / flag / version may be ? ,
2020-08-12 20:27:03 +07:00
+ 08 : 32 - bit is a pointer to a productId ? ( ie . " EP9000-UCES01421_00 " ) ,
+ 0 C : 4 x 32 - bit reserved ? all zero
2020-08-12 20:28:14 +07:00
+ 1 C : 32 - bit callback handler ? optional handler ? seems to be a valid pointer and pointing to a starting point of a function ( have a label on the disassembly )
2020-08-12 20:27:03 +07:00
+ 20 : 32 - bit a pointer to a random data ( 4 to 8 - bytes data max ? both 2 x 32 - bit seems to be a valid pointer ) . optional handler args ?
return value > = 0 and < 0 seems to be stored at a different location by the game ( valid result vs error code ? )
*/
2022-02-28 16:20:03 +07:00
int sceNpAuthCreateStartRequest ( u32 paramAddr )
2020-08-12 20:28:14 +07:00
{
2022-02-28 16:20:03 +07:00
WARN_LOG ( SCENET , " UNTESTED %s(%08x) at %08x " , __FUNCTION__ , paramAddr , currentMIPS - > pc ) ;
2020-08-12 20:28:14 +07:00
if ( ! Memory : : IsValidAddress ( paramAddr ) )
2022-02-28 16:20:03 +07:00
return hleLogError ( SCENET , SCE_NP_AUTH_ERROR_INVALID_ARGUMENT , " invalid arg " ) ;
2020-08-12 20:28:14 +07:00
SceNpAuthRequestParameter params = { } ;
int size = Memory : : Read_U32 ( paramAddr ) ;
Memory : : Memcpy ( & params , paramAddr , size ) ;
2022-02-28 16:20:03 +07:00
npServiceId = Memory : : GetCharPointer ( params . serviceIdAddr ) ;
2020-08-12 20:28:14 +07:00
2022-02-28 16:20:03 +07:00
INFO_LOG ( SCENET , " %s - Max Version: %u.%u " , __FUNCTION__ , params . version . major , params . version . minor ) ;
INFO_LOG ( SCENET , " %s - Service ID: %s " , __FUNCTION__ , Memory : : GetCharPointer ( params . serviceIdAddr ) ) ;
INFO_LOG ( SCENET , " %s - Entitlement ID: %s " , __FUNCTION__ , Memory : : GetCharPointer ( params . entitlementIdAddr ) ) ;
INFO_LOG ( SCENET , " %s - Consumed Count: %d " , __FUNCTION__ , params . consumedCount ) ;
INFO_LOG ( SCENET , " %s - Cookie (size = %d): %s " , __FUNCTION__ , params . cookieSize , Memory : : GetCharPointer ( params . cookieAddr ) ) ;
2020-08-12 20:28:14 +07:00
u32 retval = 0 ;
if ( params . size > = 32 & & params . ticketCbAddr ! = 0 ) {
bool foundHandler = false ;
struct NpAuthHandler handler ;
memset ( & handler , 0 , sizeof ( handler ) ) ;
while ( npAuthHandlers . find ( retval ) ! = npAuthHandlers . end ( ) )
+ + retval ;
handler . entryPoint = params . ticketCbAddr ;
handler . argument = params . cbArgAddr ;
for ( std : : map < int , NpAuthHandler > : : iterator it = npAuthHandlers . begin ( ) ; it ! = npAuthHandlers . end ( ) ; it + + ) {
if ( it - > second . entryPoint = = handler . entryPoint ) {
foundHandler = true ;
retval = it - > first ;
break ;
}
}
if ( ! foundHandler & & Memory : : IsValidAddress ( handler . entryPoint ) ) {
npAuthHandlers [ retval ] = handler ;
WARN_LOG ( SCENET , " %s - Added handler(%08x, %08x) : %d " , __FUNCTION__ , handler . entryPoint , handler . argument , retval ) ;
}
else {
ERROR_LOG ( SCENET , " %s - Same handler(%08x, %08x) already exists " , __FUNCTION__ , handler . entryPoint , handler . argument ) ;
}
// Patapon 3 will only Abort & Destroy AuthRequest if the ID is larger than 0. Is 0 a valid request id?
retval + + ;
// 1st Arg usually either an ID returned from Create/AddHandler function or an Event ID if the game is expecting a sequence of events.
// 2nd Arg seems to be used if not a negative number and exits the handler if it's negative (error code?)
// 3rd Arg seems to be a data (ie. 92 bytes of data?) pointer and tested for null within callback handler (optional callback args?)
u32 ticketLength = 248 ; // default ticket length? should be updated using the ticket length returned from login
notifyNpAuthHandlers ( retval , ticketLength , ( params . size > = 36 ) ? params . cbArgAddr : 0 ) ;
2020-08-12 20:27:03 +07:00
}
2020-08-12 20:28:14 +07:00
//hleDelayResult(0, "give time", 500000);
return retval ;
}
// Used within callback of sceNpAuthCreateStartRequest (arg1 = callback's args[0], arg2 = output structPtr?, arg3 = callback's args[1])
// Is this using request id for Arg1 or cbId?
// JPCSP is using length = 248 for dummy ticket
2022-02-28 16:20:03 +07:00
int sceNpAuthGetTicket ( u32 requestId , u32 bufferAddr , u32 length )
2020-08-12 20:28:14 +07:00
{
2022-02-28 16:20:03 +07:00
ERROR_LOG ( SCENET , " UNIMPL %s(%d, %08x, %d) at %08x " , __FUNCTION__ , requestId , bufferAddr , length , currentMIPS - > pc ) ;
2020-08-12 20:28:14 +07:00
if ( ! Memory : : IsValidAddress ( bufferAddr ) )
2022-02-28 16:20:03 +07:00
return hleLogError ( SCENET , SCE_NP_AUTH_ERROR_INVALID_ARGUMENT , " invalid arg " ) ;
2020-08-12 20:28:14 +07:00
int result = length ;
Memory : : Memset ( bufferAddr , 0 , length ) ;
SceNpTicket ticket = { } ;
// Dummy Login ticket returned as Login response. Dummy ticket contents were taken from https://www.psdevwiki.com/ps3/X-I-5-Ticket
ticket . header . version = TICKET_VER_2_1 ;
ticket . header . size = 0xF0 ; // size excluding the header
2022-07-20 12:40:22 +02:00
u8 * buf = Memory : : GetPointerWrite ( bufferAddr + sizeof ( ticket ) ) ;
2020-08-12 20:28:14 +07:00
int ofs = 0 ;
2022-02-28 16:20:03 +07:00
ofs + = writeTicketParam ( buf , PARAM_TYPE_STRING_ASCII , " \x4c \x47 \x56 \x3b \x81 \x39 \x4a \x22 \xd8 \x6b \xc1 \x57 \x71 \x6e \xfd \xb8 \xab \x63 \xcc \x51 " , 20 ) ; // 20 random letters, token key or SceNpSignature?
2020-08-12 20:28:14 +07:00
ofs + = writeTicketU32Param ( buf + ofs , PARAM_TYPE_INT , 0x0100 ) ; // a flags?
2022-02-28 16:20:03 +07:00
PSPTimeval tv ; //npSigninTimestamp
2020-08-12 20:28:14 +07:00
__RtcTimeOfDay ( & tv ) ;
u64 now = 1000ULL * tv . tv_sec + tv . tv_usec / 1000ULL ; // in milliseconds, since 1900?
ofs + = writeTicketU64Param ( buf + ofs , PARAM_TYPE_DATE , now ) ;
ofs + = writeTicketU64Param ( buf + ofs , PARAM_TYPE_DATE , now + 10 * 60 * 1000 ) ; // now + 10 minutes, expired time?
ofs + = writeTicketU64Param ( buf + ofs , PARAM_TYPE_LONG , 0x592e71c546e86859 ) ; // seems to be consistent, 8-bytes password hash may be? or related to entitlement? or console id?
2022-02-28 16:20:03 +07:00
ofs + = writeTicketStringParam ( buf + ofs , PARAM_TYPE_STRING , npOnlineId . c_str ( ) , 32 ) ; // username
ofs + = writeTicketParam ( buf + ofs , PARAM_TYPE_STRING_ASCII , npCountryCode , 4 ) ; // SceNpCountryCode ? ie. "fr" + 00 02
ofs + = writeTicketStringParam ( buf + ofs , PARAM_TYPE_STRING , npRegionCode , 4 ) ; // 2-char code? related to country/lang code? ie. "c9" + 00 00
ofs + = writeTicketParam ( buf + ofs , PARAM_TYPE_STRING_ASCII , npServiceId . c_str ( ) , 24 ) ;
2020-08-12 20:28:14 +07:00
int status = 0 ;
2022-02-28 16:20:03 +07:00
if ( npParentalControl = = PARENTAL_CONTROL_ENABLED ) {
2020-08-12 20:28:14 +07:00
status | = STATUS_ACCOUNT_PARENTAL_CONTROL_ENABLED ;
}
2022-02-28 16:20:03 +07:00
status | = ( npUserAge & 0x7F ) < < 24 ;
2020-08-12 20:28:14 +07:00
ofs + = writeTicketU32Param ( buf + ofs , PARAM_TYPE_INT , status ) ;
ofs + = writeTicketParam ( buf + ofs , PARAM_TYPE_NULL ) ;
ofs + = writeTicketParam ( buf + ofs , PARAM_TYPE_NULL ) ;
ticket . section . type = SECTION_TYPE_BODY ;
ticket . section . size = ofs ;
Memory : : WriteStruct ( bufferAddr , & ticket ) ;
2022-02-28 16:20:03 +07:00
SceNpTicketSection footer = { SECTION_TYPE_FOOTER , 32 } ; // footer section? ie. 32-bytes on version 2.1 containing 4-chars ASCII + 20-chars ASCII
2020-08-12 20:28:14 +07:00
Memory : : WriteStruct ( bufferAddr + sizeof ( ticket ) + ofs , & footer ) ;
ofs + = sizeof ( footer ) ;
ofs + = writeTicketParam ( buf + ofs , PARAM_TYPE_STRING_ASCII , " \x34 \xcd \x3c \xa9 " , 4 ) ;
2022-02-28 16:20:03 +07:00
ofs + = writeTicketParam ( buf + ofs , PARAM_TYPE_STRING_ASCII , " \x3a \x4b \x42 \x66 \x92 \xda \x6b \x7c \xb7 \x4c \xe8 \xd9 \x4f \x2b \x77 \x15 \x91 \xb8 \xa4 \xa9 " , 20 ) ; // 20 random letters, token key or SceNpSignature?
u8 unknownBytes [ 36 ] = { } ; // includes Language list?
2020-08-12 20:28:14 +07:00
Memory : : WriteStruct ( bufferAddr + sizeof ( ticket ) + ofs , unknownBytes ) ;
result = ticket . header . size + sizeof ( ticket . header ) ; // dummy ticket is 248 bytes
return result ;
}
// Used within callback of sceNpAuthCreateStartRequest (arg1 = structPtr?, arg2 = callback's args[1], arg3 = DLCcode? ie. "EP9000-UCES01421_00-DLL001", arg4 = Patapon 3 always set to 0?)
// Patapon 3 will loop (for each DLC?) through an array of 4+4 bytes, ID addr (pchar) + result (int). Each loop calls this function using the same ticket addr but use different ID addr (arg3) and store the return value in result field (default/initial = -1)
2022-02-28 16:20:03 +07:00
int sceNpAuthGetEntitlementById ( u32 ticketBufferAddr , u32 ticketLength , u32 entitlementIdAddr , u32 arg4 )
2020-08-12 20:28:14 +07:00
{
2022-02-28 16:20:03 +07:00
ERROR_LOG ( SCENET , " UNIMPL %s(%08x, %d, %08x, %d) " , __FUNCTION__ , ticketBufferAddr , ticketLength , entitlementIdAddr , arg4 ) ;
INFO_LOG ( SCENET , " %s - Entitlement ID: %s " , __FUNCTION__ , Memory : : GetCharPointer ( entitlementIdAddr ) ) ;
2020-08-12 20:28:14 +07:00
// Do we return the entitlement through function result? or update the ticket content? or replace the arg3 data with SceNpEntitlement struct?
return 1 ; // dummy value assuming it's a boolean/flag, since we don't know how to return the entitlement result yet
2020-08-12 20:27:03 +07:00
}
2022-02-28 16:20:03 +07:00
int sceNpAuthAbortRequest ( int requestId )
2020-08-12 20:27:03 +07:00
{
2022-02-28 16:20:03 +07:00
WARN_LOG ( SCENET , " UNTESTED %s(%i) " , __FUNCTION__ , requestId ) ;
2020-08-12 20:28:14 +07:00
// TODO: Disconnect HTTPS connection & cancel the callback event
std : : lock_guard < std : : recursive_mutex > npAuthGuard ( npAuthEvtMtx ) ;
for ( auto it = npAuthEvents . begin ( ) ; it ! = npAuthEvents . end ( ) ; ) {
( it - > data [ 0 ] = = requestId ) ? it = npAuthEvents . erase ( it ) : + + it ;
}
2022-02-28 16:20:03 +07:00
2020-08-12 20:27:03 +07:00
return 0 ;
}
2022-02-28 16:20:03 +07:00
int sceNpAuthDestroyRequest ( int requestId )
2020-08-12 20:27:03 +07:00
{
2022-02-28 16:20:03 +07:00
WARN_LOG ( SCENET , " UNTESTED %s(%i) " , __FUNCTION__ , requestId ) ;
2020-08-12 20:28:14 +07:00
// Remove callback handler
int handlerID = requestId - 1 ;
if ( npAuthHandlers . find ( handlerID ) ! = npAuthHandlers . end ( ) ) {
npAuthHandlers . erase ( handlerID ) ;
WARN_LOG ( SCENET , " %s: Deleted handler %d " , __FUNCTION__ , handlerID ) ;
}
else {
ERROR_LOG ( SCENET , " %s: Invalid request ID %d " , __FUNCTION__ , requestId ) ;
}
2022-02-28 16:20:03 +07:00
2020-08-12 20:28:14 +07:00
// Patapon 3 is checking for error code 0x80550402
2013-11-14 22:43:00 +08:00
return 0 ;
}
2022-02-28 16:20:03 +07:00
int sceNpAuthGetTicketParam ( u32 ticketBufPtr , int ticketLen , int paramNum , u32 bufferPtr )
{
ERROR_LOG ( SCENET , " UNIMPL %s(%08x, %0d, %d, %08x) at %08x " , __FUNCTION__ , ticketBufPtr , ticketLen , paramNum , bufferPtr , currentMIPS - > pc ) ;
const u32 PARAM_BUFFER_MAX_SIZE = 256 ;
Memory : : Memset ( bufferPtr , 0 , PARAM_BUFFER_MAX_SIZE ) ; // JPCSP: This clear is always done, even when an error is returned
if ( paramNum < 0 | | paramNum > = NUMBER_PARAMETERS ) {
return SCE_NP_MANAGER_ERROR_INVALID_ARGUMENT ;
}
SceNpTicket * ticket = ( SceNpTicket * ) Memory : : GetPointer ( ticketBufPtr ) ;
u32 inbuf = ticketBufPtr ;
inbuf + = sizeof ( ticket - > header ) ;
inbuf + = ticket - > section . size + sizeof ( ticket - > section ) ;
u32 outbuf = bufferPtr ;
for ( int i = 0 ; i < paramNum ; i + + ) {
SceNpTicketParamData * ticketParam = ( SceNpTicketParamData * ) Memory : : GetPointer ( inbuf ) ;
u32 sz = ( u32 ) sizeof ( SceNpTicketParamData ) + ticketParam - > length ;
Memory : : Memcpy ( outbuf , inbuf , sz ) ;
2022-08-06 03:10:59 +07:00
DEBUG_LOG ( SCENET , " %s - Param #%d: Type = %04hx, Length = %u " , __FUNCTION__ , i , static_cast < unsigned short > ( ticketParam - > type ) , static_cast < unsigned int > ( ticketParam - > length ) ) ;
2022-02-28 16:20:03 +07:00
outbuf + = sz ;
inbuf + = sz ;
if ( outbuf - bufferPtr > = PARAM_BUFFER_MAX_SIZE | | inbuf - ticketBufPtr > = ( u32 ) ticketLen )
break ;
}
return 0 ;
}
2020-08-12 20:28:14 +07:00
2013-04-29 12:40:09 +09:00
const HLEFunction sceNpAuth [ ] = {
2022-02-28 16:20:03 +07:00
{ 0X4EC1F667 , & WrapI_V < sceNpAuthTerm > , " sceNpAuthTerm " , ' i ' , " " } ,
{ 0XA1DE86F8 , & WrapI_UUU < sceNpAuthInit > , " sceNpAuthInit " , ' i ' , " xxx " } ,
{ 0XF4531ADC , & WrapI_U < sceNpAuthGetMemoryStat > , " sceNpAuthGetMemoryStat " , ' i ' , " x " } ,
{ 0XCD86A656 , & WrapI_U < sceNpAuthCreateStartRequest > , " sceNpAuthCreateStartRequest " , ' i ' , " x " } ,
{ 0X3F1C1F70 , & WrapI_UUU < sceNpAuthGetTicket > , " sceNpAuthGetTicket " , ' i ' , " xxx " } ,
{ 0X6900F084 , & WrapI_UUUU < sceNpAuthGetEntitlementById > , " sceNpAuthGetEntitlementById " , ' i ' , " xxxx " } ,
{ 0XD99455DD , & WrapI_I < sceNpAuthAbortRequest > , " sceNpAuthAbortRequest " , ' i ' , " i " } ,
{ 0X72BB0467 , & WrapI_I < sceNpAuthDestroyRequest > , " sceNpAuthDestroyRequest " , ' i ' , " i " } ,
{ 0x5A3CB57A , & WrapI_UIIU < sceNpAuthGetTicketParam > , " sceNpAuthGetTicketParam " , ' i ' , " xiix " } ,
{ 0x75FB0AE3 , nullptr , " sceNpAuthGetEntitlementIdList " , ' i ' , " " } ,
2013-04-29 12:40:09 +09:00
} ;
2013-05-15 19:49:34 +08:00
void Register_sceNpAuth ( )
2013-04-29 12:40:09 +09:00
{
RegisterModule ( " sceNpAuth " , ARRAY_SIZE ( sceNpAuth ) , sceNpAuth ) ;
}
2020-08-12 20:27:03 +07:00
static int sceNpServiceTerm ( )
2013-11-14 22:43:00 +08:00
{
// No parameters
2022-02-28 16:20:03 +07:00
ERROR_LOG ( SCENET , " UNIMPL %s() " , __FUNCTION__ ) ;
2013-11-14 22:43:00 +08:00
return 0 ;
}
2020-08-12 20:27:03 +07:00
static int sceNpServiceInit ( u32 poolSize , u32 stackSize , u32 threadPrio )
2013-11-14 22:43:00 +08:00
{
2022-02-28 16:20:03 +07:00
ERROR_LOG ( SCENET , " UNIMPL %s(%08x, %08x, %08x) " , __FUNCTION__ , poolSize , stackSize , threadPrio ) ;
2013-11-14 22:43:00 +08:00
return 0 ;
}
2022-02-28 16:20:03 +07:00
// FIXME: On Patapon 3 the Arg is pointing to a String, but based on RPCS3 the Arg is an Id integer ?
2020-08-12 20:28:14 +07:00
static int sceNpLookupCreateTransactionCtx ( u32 lookupTitleCtxIdAddr )
{
2022-02-28 16:20:03 +07:00
ERROR_LOG ( SCENET , " UNIMPL %s(%08x) " , __FUNCTION__ , lookupTitleCtxIdAddr ) ;
2020-08-12 20:28:14 +07:00
INFO_LOG ( SCENET , " %s - Title ID: %s " , __FUNCTION__ , Memory : : GetCharPointer ( lookupTitleCtxIdAddr ) ) ;
// Patapon 3 will only Destroy if returned Id > 0. Is 0 a valid id?
return 1 ; // returning dummy transaction id
}
// transId: id returned from sceNpLookupCreateTransactionCtx
2022-02-28 16:20:03 +07:00
static int sceNpLookupDestroyTransactionCtx ( s32 transId )
2020-08-12 20:28:14 +07:00
{
2022-02-28 16:20:03 +07:00
ERROR_LOG ( SCENET , " UNIMPL %s(%d) " , __FUNCTION__ , transId ) ;
2020-08-12 20:28:14 +07:00
return 0 ;
}
// transId: id returned from sceNpLookupCreateTransactionCtx
// Patapon 3 always set Arg5 to 0
// Addr args have something to do with GameUpdate?
2022-02-28 16:20:03 +07:00
// FIXME: maxSize and contentLength are u64 based on https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Cell/Modules/sceNp.cpp ? But on Patapon 3 optionAddr will be deadbeef if maxSize is u64 ?
static int sceNpLookupTitleSmallStorage ( s32 transId , u32 dataAddr , u32 maxSize , u32 contentLengthAddr , u32 optionAddr )
2020-08-12 20:28:14 +07:00
{
2022-02-28 16:20:03 +07:00
ERROR_LOG ( SCENET , " UNIMPL %s(%d, %08x, %d, %08x[%d], %08x) at %08x " , __FUNCTION__ , transId , dataAddr , maxSize , contentLengthAddr , ( Memory : : IsValidAddress ( contentLengthAddr ) ? Memory : : Read_U32 ( contentLengthAddr ) : 0 ) , optionAddr , currentMIPS - > pc ) ;
return 0 ;
}
// On Resistance Retribution:
// unknownAddr pointing to a struct of:
// 32-bit pointer (ie. 08efc6c4)? or a timestamp combined with the next 32-bit value?
// 32-bit pointer (ie. 08f9d101)? but unaligned (the lowest byte seems to be intentionally set to 1)? so probably not a pointer, may be a timestamp combined with previous 32-bit value?
// 32-bit pointer? Seems to be pointing to dummy ticket data generated by sceNpAuthGetTicket
// 32-bit value (248) dummy ticket length from NpAuth Ticket?
// There could be more data in the struct? (at least 48-bytes?)
static int sceNpRosterCreateRequest ( u32 unknownAddr )
{
ERROR_LOG ( SCENET , " UNIMPL %s(%08x) at %08x " , __FUNCTION__ , unknownAddr , currentMIPS - > pc ) ;
return 1 ; // returning dummy roster id
}
// On Resistance Retribution:
// unknown1 set to 50 (max entries?),
// unknown2 set to 0,
// unknown3Addr pointing to unset buffer? (output entry data? usually located right after number of entries?),
// unknown4Addr pointing to 32-bit value set to 0 (output number of entries?),
// unknown5Addr pointing to zeroed buffer?,
// unknown6 set to 0
static int sceNpRosterGetFriendListEntry ( s32 rosterId , u32 unknown1 , u32 unknown2 , u32 unknown3Addr , u32 unknown4Addr , u32 unknown5Addr , u32 unknown6 )
{
ERROR_LOG ( SCENET , " UNIMPL %s(%d, %08x, %08x, %08x, %08x, %08x, %08x) at %08x " , __FUNCTION__ , rosterId , unknown1 , unknown2 , unknown3Addr , unknown4Addr , unknown5Addr , unknown6 , currentMIPS - > pc ) ;
return 0 ;
}
static int sceNpRosterAbort ( s32 rosterId )
{
ERROR_LOG ( SCENET , " UNIMPL %s(%d) at %08x " , __FUNCTION__ , rosterId , currentMIPS - > pc ) ;
return 0 ;
}
static int sceNpRosterDeleteRequest ( s32 rosterId )
{
ERROR_LOG ( SCENET , " UNIMPL %s(%d) at %08x " , __FUNCTION__ , rosterId , currentMIPS - > pc ) ;
2020-08-12 20:28:14 +07:00
return 0 ;
}
2013-04-29 12:40:09 +09:00
const HLEFunction sceNpService [ ] = {
2022-02-28 16:20:03 +07:00
{ 0X00ACFAC3 , & WrapI_V < sceNpServiceTerm > , " sceNpServiceTerm " , ' i ' , " " } ,
{ 0X0F8F5821 , & WrapI_UUU < sceNpServiceInit > , " sceNpServiceInit " , ' i ' , " xxx " } ,
{ 0X5494274B , & WrapI_U < sceNpLookupCreateTransactionCtx > , " sceNpLookupCreateTransactionCtx " , ' i ' , " x " } ,
{ 0XA670D3A3 , & WrapI_I < sceNpLookupDestroyTransactionCtx > , " sceNpLookupDestroyTransactionCtx " , ' i ' , " i " } ,
{ 0XC76F55ED , & WrapI_IUUUU < sceNpLookupTitleSmallStorage > , " sceNpLookupTitleSmallStorage " , ' i ' , " ixxxx " } ,
{ 0XBE22EEA3 , & WrapI_U < sceNpRosterCreateRequest > , " sceNpRosterCreateRequest " , ' i ' , " x " } ,
{ 0X4E851B10 , & WrapI_IUUUUUU < sceNpRosterGetFriendListEntry > , " sceNpRosterGetFriendListEntry " , ' i ' , " ixxxxxx " } ,
{ 0X5F5E32AF , & WrapI_I < sceNpRosterAbort > , " sceNpRosterAbort " , ' i ' , " i " } ,
{ 0X66C64821 , & WrapI_I < sceNpRosterDeleteRequest > , " sceNpRosterDeleteRequest " , ' i ' , " i " } ,
2013-04-29 12:40:09 +09:00
} ;
void Register_sceNpService ( )
{
RegisterModule ( " sceNpService " , ARRAY_SIZE ( sceNpService ) , sceNpService ) ;
}
2022-02-28 16:20:03 +07:00
// TODO: Moves NpCommerce2-related stuff to sceNpCommerce2.cpp
2013-04-29 12:40:09 +09:00
const HLEFunction sceNpCommerce2 [ ] = {
2020-08-12 20:27:03 +07:00
{ 0X005B5F20 , nullptr , " sceNpCommerce2GetProductInfoStart " , ' ? ' , " " } ,
{ 0X0E9956E3 , nullptr , " sceNpCommerce2Init " , ' ? ' , " " } ,
{ 0X1888A9FE , nullptr , " sceNpCommerce2DestroyReq " , ' ? ' , " " } ,
{ 0X1C952DCB , nullptr , " sceNpCommerce2GetGameProductInfo " , ' ? ' , " " } ,
{ 0X2B25F6E9 , nullptr , " sceNpCommerce2CreateSessionStart " , ' ? ' , " " } ,
{ 0X3371D5F1 , nullptr , " sceNpCommerce2GetProductInfoCreateReq " , ' ? ' , " " } ,
{ 0X4ECD4503 , nullptr , " sceNpCommerce2CreateSessionCreateReq " , ' ? ' , " " } ,
{ 0X590A3229 , nullptr , " sceNpCommerce2GetSessionInfo " , ' ? ' , " " } ,
{ 0X6F1FE37F , nullptr , " sceNpCommerce2CreateCtx " , ' ? ' , " " } ,
{ 0XA5A34EA4 , nullptr , " sceNpCommerce2Term " , ' ? ' , " " } ,
{ 0XAA4A1E3D , nullptr , " sceNpCommerce2GetProductInfoGetResult " , ' ? ' , " " } ,
{ 0XBC61FFC8 , nullptr , " sceNpCommerce2CreateSessionGetResult " , ' ? ' , " " } ,
{ 0XC7F32242 , nullptr , " sceNpCommerce2AbortReq " , ' ? ' , " " } ,
{ 0XF2278B90 , nullptr , " sceNpCommerce2GetGameSkuInfoFromGameProductInfo " , ' ? ' , " " } ,
{ 0XF297AB9C , nullptr , " sceNpCommerce2DestroyCtx " , ' ? ' , " " } ,
{ 0XFC30C19E , nullptr , " sceNpCommerce2InitGetProductInfoResult " , ' ? ' , " " } ,
2013-04-29 12:40:09 +09:00
} ;
void Register_sceNpCommerce2 ( )
{
RegisterModule ( " sceNpCommerce2 " , ARRAY_SIZE ( sceNpCommerce2 ) , sceNpCommerce2 ) ;
2020-08-12 20:27:03 +07:00
}
2022-02-28 16:20:03 +07:00