/*---------------------------------------------------------------------------* Project: Horizon File: Util.cpp Copyright (C)2010-2011 Nintendo Co., Ltd. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Rev$ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Util.h" #include "FileName.h" #include "CommonLogger.h" #include "HeapManager.h" #include "FileTransfer.h" namespace common { Util::Util() : m_FriendCode(0), mp_Ivs(NULL), m_SizeofIvs(0), m_SerialNoWithoutCGLen(0), m_BatteryRemain(100), m_CanReadSerialNumber(false), m_CanReadIvs( false), m_HasReadFriendCode(false) { } Util::~Util() { } void Util::InitializeForBackup() { Initialize(); } void Util::InitializeForRestore() { Initialize(); // friendsの初期化 nn::Result result = nn::friends::detail::Initialize(); // フレンドコードの取得 nn::friends::CTR::FriendKey friendKey; result = nn::friends::CTR::GetMyFriendKey(&friendKey); COMMON_LOGGER_RESULT_IF_FAILED(result); m_FriendCode = nn::friends::CTR::FriendKeyToFriendCode(friendKey); m_HasReadFriendCode = true; } void Util::Initialize() { nn::Result result; // mcuの初期化 nn::mcu::CTR::InitializeHwCheck(&m_McuSession); mp_Mcu = new nn::mcu::CTR::HwCheck(m_McuSession); // シリアルナンバーの取得 std::memset(m_SerialNo, '\0', nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN); result = nn::cfg::CTR::system::GetSerialNo(m_SerialNo); if(result.IsSuccess()) { m_CanReadSerialNumber = true; } COMMON_LOGGER_RESULT_IF_FAILED(result); AddCheckDigit(reinterpret_cast(m_SerialNo)); // デバイスIDの取得 result = nn::ps::CTR::GetDeviceId(&m_DeviceId); COMMON_LOGGER_RESULT_IF_FAILED(result); // リージョンの取得 m_Region = nn::cfg::CTR::GetRegion(); // バージョンの取得 common::GetSystemVersion(&m_VerData, m_Region); // IVSの取得 ReadIvs(m_VerData.cup.majorVersion); // MACアドレスの取得 nn::nwm::Mac mac; result = nn::nwm::GetMacAddress(mac); COMMON_LOGGER_RESULT_IF_FAILED(result); mac.GetString(m_MacAddress); COMMON_LOGGER_RESULT_IF_FAILED(result); } void Util::FinalizeForBackup() { Finalize(); } void Util::FinalizeForRestore() { nn::friends::detail::Finalize(); } void Util::Finalize() { nn::mcu::CTR::FinalizeHwCheck(&m_McuSession); } void Util::ReadIvs(u8 cupMajorVersion) { if (cupMajorVersion < common::CUP_MAJOR_VER_2ND_NUP) { nn::Result result; // 完全性検証SEEDの取得 result = nn::fs::MountSpecialArchive(common::NAND_ARCHIVE_NAME, nn::fs::CTR::ARCHIVE_TYPE_CTR_NAND); if (result.IsSuccess()) { nn::fs::FileInputStream fis; result = fis.TryInitialize(common::IVS_NAND_PATHNAME); if (result.IsSuccess()) { s64 fileSize = fis.GetSize(); s32 ret; void* addr = NULL; addr = ForceAllocate(fileSize); if (addr != NULL) { mp_Ivs = addr; m_SizeofIvs = fileSize; result = fis.TryRead(&ret, addr, fileSize); if (result.IsSuccess()) { m_CanReadIvs = true; } // 後でIVSを参照するのでFreeしない } } fis.Finalize(); } // 一旦アンマウントしておく nn::fs::Unmount(common::NAND_ARCHIVE_NAME); } else { nn::Result result; void* pSeed = ForceAllocate(sizeof(nn::fs::CTR::IntegrityVerificationSeed)); if(pSeed != NULL) { result = nn::fs::CTR::ExportIntegrityVerificationSeed( reinterpret_cast(pSeed)); if(result.IsSuccess()) { mp_Ivs = pSeed; m_SizeofIvs = sizeof(nn::fs::CTR::IntegrityVerificationSeed); m_CanReadIvs = true; } // 後でIVSを参照するのでFreeしない } } } // NULL終端されたシリアルナンバーを受け取る // NULL終端された場所にチェックデジットを付加して新たにNULL終端する void Util::AddCheckDigit(char* serial) { m_SerialNoWithoutCGLen = std::strlen(serial); u8 digit = 0; bool odd = true; for(u8 i = m_SerialNoWithoutCGLen - 1; i > 0 && std::isdigit(serial[i]); i--) { if(odd) { digit += (serial[i] - '0') * 3; } else { digit += (serial[i] - '0'); } odd = !odd; } if(digit % 10 != 0) { serial[m_SerialNoWithoutCGLen] = 10 - (digit % 10) + '0'; } else { serial[m_SerialNoWithoutCGLen] = '0'; } serial[m_SerialNoWithoutCGLen + 1] = '\0'; } // /Nintendo 3DS/6ea6b9d6ab70493ea9edd8b947d5d819/853600b24760a87f534430320002544d // から、6ea6b9d6ab70493ea9edd8b947d5d819 を取り出す void Util::GetSaveDataDirectoryRoot(::std::string& sysSaveRoot) { nn::Result result; wchar_t path[512]; result = nn::fs::GetSdmcCtrRootPath(path, sizeof(path)); COMMON_LOGGER_RETURN_VOID_IF_FAILED(result); NN_LOG("%ls\n", path); std::string sdmcRootPath = common::GetCharStr(path); sysSaveRoot = sdmcRootPath.substr(sizeof("Nintendo 3DS/"), 32); NN_LOG("saveRoot = %s\n", sysSaveRoot.c_str()); } bool Util::IsAdapterConnected() { static nn::os::Tick last(0); static bool lastResult = false; const u8 UPDATE_INTERVAL = 100; nn::os::Tick now = nn::os::Tick::GetSystemCurrent(); if(last == 0 || (now - last).ToTimeSpan().GetMilliSeconds() > UPDATE_INTERVAL) { u8 buf; nn::Result result = mp_Mcu->ReadByReceive(nn::drivers::mcu::CTR::MCU_PERIPHERAL_STATUS_ADDR, &buf, sizeof(buf)); if(result.IsSuccess()) { last = now; lastResult = buf & nn::drivers::mcu::CTR::MCU_STATUS_ADAPTER_MASK; } } return lastResult; } bool Util::IsBatteryLower() { m_BatteryRemain = GetBatteryRemain(); return m_BatteryRemain <= 10; } bool Util::CanReadIVS() { return m_CanReadIvs; } bool Util::CanReadSerialNumber() { return m_CanReadSerialNumber; } void Util::GetSerialNumber(u8** serial, size_t* size) { *serial = m_SerialNo; *size = nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN; } u8* Util::GetSerialNumber() { return m_SerialNo; } void Util::GetSerialNumberWithoutCD(u8* serial) { std::memcpy(serial, m_SerialNo, nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN); serial[m_SerialNoWithoutCGLen] = '\0'; } void Util::GetIvs(void** ivs, size_t* size) { *ivs = mp_Ivs; *size = m_SizeofIvs; } bit32 Util::GetDeviceId() { return m_DeviceId; } u8 Util::GetCupMajorVersion() { return m_VerData.cup.majorVersion; } u8 Util::GetCupMinorVersion() { return m_VerData.cup.minorVersion; } u8 Util::GetCupMicroVersion() { return m_VerData.cup.microVersion; } u8 Util::GetNupVersion() { return m_VerData.nup.majorVersion; } nn::Handle Util::GetMcuHandle() { return m_McuSession; } u32 Util::GetBatteryRemain() { u8 remain; mp_Mcu->GetBatteryRemain(&remain); return remain; } u64 Util::GetInfraDeviceId() { bit64 infraDeviceId; infraDeviceId = m_DeviceId + common::INFRA_DEVICE_ID_OFFSET; return infraDeviceId; } u64 Util::GetFriendcode() { return m_FriendCode; } char8* Util::GetMacAddress() { return m_MacAddress; } nn::cfg::CTR::CfgRegionCode Util::GetRegion() { return m_Region; } const char* Util::GetRegionCodeA3() { return nn::cfg::GetRegionCodeA3(m_Region); } void Util::GetVersionData(common::VerDef* version) { *version = m_VerData; } bool Util::HasReadFriendCode() { return m_HasReadFriendCode; } nn::Result PrintNetworkSetting() { nn::Result result; nn::ac::NetworkSetting networkSetting; result = nn::ac::LoadNetworkSetting(0, networkSetting); COMMON_LOGGER("SSID: %s\n", networkSetting.wireless.essidSecurity.ssid); COMMON_LOGGER("DNS : %d.%d.%d.%d\n", networkSetting.ip.dns[0][0], networkSetting.ip.dns[0][1], networkSetting.ip.dns[0][2], networkSetting.ip.dns[0][3]); return result; } nn::Result InitializeNetwork(void) { nn::Result result; nn::ac::Config config; // 未初期化の時だけ初期化する if(!nn::ac::IsInitializedInternal()) { result = nn::ac::InitializeInternal(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); } // 接続要求用のパラメータを作成 result = nn::ac::CreateDefaultConfig(&config); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); // デバッグ用に接続テストを無効化 nn::ac::DebugSetNetworkArea(&config, nn::ac::NETWORK_AREA_LAN); // 接続要求を発行 result = nn::ac::ConnectWithoutEula(config); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); return nn::ResultSuccess(); } nn::Result FinalizeNetwork(void) { nn::Result result; // 接続要求用のパラメータを作成 result = nn::ac::Close(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); result = nn::ac::FinalizeInternal(); COMMON_LOGGER_RETURN_RESULT_IF_FAILED(result); return nn::ResultSuccess(); } }