IPCCommandResult ES::ImportTitleCancel(Context& context, const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(0, 0)) return GetDefaultReply(ES_EINVAL); return GetDefaultReply(ImportTitleCancel(context)); }
IPCCommandResult ES::DeleteSharedContent(const IOCtlVRequest& request) { std::array<u8, 20> sha1; if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sha1.size()) return GetDefaultReply(ES_EINVAL); Memory::CopyFromEmu(sha1.data(), request.in_vectors[0].address, request.in_vectors[0].size); return GetDefaultReply(DeleteSharedContent(sha1)); }
IPCCommandResult ES::DeleteTitle(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 8) return GetDefaultReply(ES_EINVAL); const u64 title_id = Memory::Read_U64(request.in_vectors[0].address); return GetDefaultReply(DeleteTitle(title_id)); }
IPCCommandResult ES::ExportContentEnd(Context& context, const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != 4) return GetDefaultReply(ES_EINVAL); const u32 content_fd = Memory::Read_U32(request.in_vectors[0].address); return GetDefaultReply(ExportContentEnd(context, content_fd)); }
IPCCommandResult ES::GetTitleCount(const std::vector<u64>& titles, const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != 4) return GetDefaultReply(ES_EINVAL); Memory::Write_U32(static_cast<u32>(titles.size()), request.io_vectors[0].address); return GetDefaultReply(IPC_SUCCESS); }
IPCCommandResult ES::GetTMDStoredContentsCount(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 1)) return GetDefaultReply(ES_EINVAL); std::vector<u8> tmd_bytes(request.in_vectors[0].size); Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size()); return GetStoredContentsCount(IOS::ES::TMDReader{std::move(tmd_bytes)}, request); }
IPCCommandResult ES::DeleteTicket(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 0) || request.in_vectors[0].size != sizeof(IOS::ES::TicketView)) { return GetDefaultReply(ES_EINVAL); } return GetDefaultReply(DeleteTicket(Memory::GetPointer(request.in_vectors[0].address))); }
IPCCommandResult ES::ImportContentBegin(Context& context, const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(2, 0)) return GetDefaultReply(ES_EINVAL); u64 title_id = Memory::Read_U64(request.in_vectors[0].address); u32 content_id = Memory::Read_U32(request.in_vectors[1].address); return GetDefaultReply(ImportContentBegin(context, title_id, content_id)); }
IPCCommandResult ES::DeleteContent(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(2, 0) || request.in_vectors[0].size != sizeof(u64) || request.in_vectors[1].size != sizeof(u32)) { return GetDefaultReply(ES_EINVAL); } return GetDefaultReply(DeleteContent(Memory::Read_U64(request.in_vectors[0].address), Memory::Read_U32(request.in_vectors[1].address))); }
IPCCommandResult ES::ImportContentData(Context& context, const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(2, 0)) return GetDefaultReply(ES_EINVAL); u32 content_fd = Memory::Read_U32(request.in_vectors[0].address); u8* data_start = Memory::GetPointer(request.in_vectors[1].address); return GetDefaultReply( ImportContentData(context, content_fd, data_start, request.in_vectors[1].size)); }
IPCCommandResult ES::GetSharedContentsCount(const IOCtlVRequest& request) const { if (!request.HasNumberOfValidVectors(0, 1) || request.io_vectors[0].size != sizeof(u32)) return GetDefaultReply(ES_EINVAL); const u32 count = GetSharedContentsCount(); Memory::Write_U32(count, request.io_vectors[0].address); INFO_LOG(IOS_ES, "GetSharedContentsCount: %u contents", count); return GetDefaultReply(IPC_SUCCESS); }
IPCCommandResult ES::GetStoredContents(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(2, 1) || request.in_vectors[0].size != sizeof(u64)) return GetDefaultReply(ES_EINVAL); const u64 title_id = Memory::Read_U64(request.in_vectors[0].address); const IOS::ES::TMDReader tmd = FindInstalledTMD(title_id); if (!tmd.IsValid()) return GetDefaultReply(FS_ENOENT); return GetStoredContents(tmd, request); }
IPCCommandResult ES::ExportTitleInit(Context& context, const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != 8) return GetDefaultReply(ES_EINVAL); const u64 title_id = Memory::Read_U64(request.in_vectors[0].address); u8* tmd_bytes = Memory::GetPointer(request.io_vectors[0].address); const u32 tmd_size = request.io_vectors[0].size; return GetDefaultReply(ExportTitleInit(context, title_id, tmd_bytes, tmd_size)); }
IPCCommandResult ES::GetBoot2Version(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(0, 1)) return GetDefaultReply(ES_EINVAL); INFO_LOG(IOS_ES, "IOCTL_ES_GETBOOT2VERSION"); // as of 26/02/2012, this was latest bootmii version Memory::Write_U32(4, request.io_vectors[0].address); return GetDefaultReply(IPC_SUCCESS); }
IPCCommandResult ES::ImportTmd(Context& context, const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 0)) return GetDefaultReply(ES_EINVAL); if (!IOS::ES::IsValidTMDSize(request.in_vectors[0].size)) return GetDefaultReply(ES_EINVAL); std::vector<u8> tmd(request.in_vectors[0].size); Memory::CopyFromEmu(tmd.data(), request.in_vectors[0].address, request.in_vectors[0].size); return GetDefaultReply(ImportTmd(context, tmd)); }
IPCCommandResult ES::GetTitles(const std::vector<u64>& titles, const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 1)) return GetDefaultReply(ES_EINVAL); const size_t max_count = Memory::Read_U32(request.in_vectors[0].address); for (size_t i = 0; i < std::min(max_count, titles.size()); i++) { Memory::Write_U64(titles[i], request.io_vectors[0].address + static_cast<u32>(i) * sizeof(u64)); INFO_LOG(IOS_ES, " title %016" PRIx64, titles[i]); } return GetDefaultReply(IPC_SUCCESS); }
IPCCommandResult ES::ExportContentData(Context& context, const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != 4 || request.io_vectors[0].size == 0) { return GetDefaultReply(ES_EINVAL); } const u32 content_fd = Memory::Read_U32(request.in_vectors[0].address); u8* data = Memory::GetPointer(request.io_vectors[0].address); const u32 bytes_to_read = request.io_vectors[0].size; return GetDefaultReply(ExportContentData(context, content_fd, data, bytes_to_read)); }
IPCCommandResult ES::GetSharedContents(const IOCtlVRequest& request) const { if (!request.HasNumberOfValidVectors(1, 1) || request.in_vectors[0].size != sizeof(u32)) return GetDefaultReply(ES_EINVAL); const u32 max_count = Memory::Read_U32(request.in_vectors[0].address); if (request.io_vectors[0].size != 20 * max_count) return GetDefaultReply(ES_EINVAL); const std::vector<std::array<u8, 20>> hashes = GetSharedContents(); const u32 count = std::min(static_cast<u32>(hashes.size()), max_count); Memory::CopyToEmu(request.io_vectors[0].address, hashes.data(), 20 * count); INFO_LOG(IOS_ES, "GetSharedContents: %u contents (%u requested)", count, max_count); return GetDefaultReply(IPC_SUCCESS); }
IPCCommandResult ES::GetStoredTMDSize(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(1, 1)) return GetDefaultReply(ES_EINVAL); const u64 title_id = Memory::Read_U64(request.in_vectors[0].address); const IOS::ES::TMDReader tmd = FindInstalledTMD(title_id); if (!tmd.IsValid()) return GetDefaultReply(FS_ENOENT); const u32 tmd_size = static_cast<u32>(tmd.GetBytes().size()); Memory::Write_U32(tmd_size, request.io_vectors[0].address); INFO_LOG(IOS_ES, "GetStoredTMDSize: %u bytes for %016" PRIx64, tmd_size, title_id); return GetDefaultReply(IPC_SUCCESS); }
IPCCommandResult ES::GetStoredTMD(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(2, 1)) return GetDefaultReply(ES_EINVAL); const u64 title_id = Memory::Read_U64(request.in_vectors[0].address); const IOS::ES::TMDReader tmd = FindInstalledTMD(title_id); if (!tmd.IsValid()) return GetDefaultReply(FS_ENOENT); // TODO: actually use this param in when writing to the outbuffer :/ const u32 MaxCount = Memory::Read_U32(request.in_vectors[1].address); const std::vector<u8>& raw_tmd = tmd.GetBytes(); if (raw_tmd.size() != request.io_vectors[0].size) return GetDefaultReply(ES_EINVAL); Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size()); INFO_LOG(IOS_ES, "GetStoredTMD: title %016" PRIx64 " (buffer size: %u)", title_id, MaxCount); return GetDefaultReply(IPC_SUCCESS); }
IPCCommandResult ES::GetTMDStoredContents(const IOCtlVRequest& request) { if (!request.HasNumberOfValidVectors(2, 1)) return GetDefaultReply(ES_EINVAL); std::vector<u8> tmd_bytes(request.in_vectors[0].size); Memory::CopyFromEmu(tmd_bytes.data(), request.in_vectors[0].address, tmd_bytes.size()); const IOS::ES::TMDReader tmd{std::move(tmd_bytes)}; if (!tmd.IsValid()) return GetDefaultReply(ES_EINVAL); std::vector<u8> cert_store; ReturnCode ret = ReadCertStore(&cert_store); if (ret != IPC_SUCCESS) return GetDefaultReply(ret); ret = VerifyContainer(VerifyContainerType::TMD, VerifyMode::UpdateCertStore, tmd, cert_store); if (ret != IPC_SUCCESS) return GetDefaultReply(ret); return GetStoredContents(tmd, request); }
IPCCommandResult NetIPTop::HandleGetAddressInfoRequest(const IOCtlVRequest& request) { addrinfo hints; if (request.in_vectors.size() > 2 && request.in_vectors[2].size) { hints.ai_flags = Memory::Read_U32(request.in_vectors[2].address); hints.ai_family = Memory::Read_U32(request.in_vectors[2].address + 0x4); hints.ai_socktype = Memory::Read_U32(request.in_vectors[2].address + 0x8); hints.ai_protocol = Memory::Read_U32(request.in_vectors[2].address + 0xC); hints.ai_addrlen = Memory::Read_U32(request.in_vectors[2].address + 0x10); hints.ai_canonname = nullptr; hints.ai_addr = nullptr; hints.ai_next = nullptr; } // getaddrinfo allows a null pointer for the nodeName or serviceName strings // So we have to do a bit of juggling here. std::string nodeNameStr; const char* pNodeName = nullptr; if (request.in_vectors.size() > 0 && request.in_vectors[0].size > 0) { nodeNameStr = Memory::GetString(request.in_vectors[0].address, request.in_vectors[0].size); pNodeName = nodeNameStr.c_str(); } std::string serviceNameStr; const char* pServiceName = nullptr; if (request.in_vectors.size() > 1 && request.in_vectors[1].size > 0) { serviceNameStr = Memory::GetString(request.in_vectors[1].address, request.in_vectors[1].size); pServiceName = serviceNameStr.c_str(); } addrinfo* result = nullptr; int ret = getaddrinfo( pNodeName, pServiceName, (request.in_vectors.size() > 2 && request.in_vectors[2].size) ? &hints : nullptr, &result); u32 addr = request.io_vectors[0].address; u32 sockoffset = addr + 0x460; if (ret == 0) { constexpr size_t WII_ADDR_INFO_SIZE = 0x20; for (addrinfo* result_iter = result; result_iter != nullptr; result_iter = result_iter->ai_next) { Memory::Write_U32(result_iter->ai_flags, addr); Memory::Write_U32(result_iter->ai_family, addr + 0x04); Memory::Write_U32(result_iter->ai_socktype, addr + 0x08); Memory::Write_U32(result_iter->ai_protocol, addr + 0x0C); Memory::Write_U32((u32)result_iter->ai_addrlen, addr + 0x10); // what to do? where to put? the buffer of 0x834 doesn't allow space for this Memory::Write_U32(/*result->ai_cannonname*/ 0, addr + 0x14); if (result_iter->ai_addr) { Memory::Write_U32(sockoffset, addr + 0x18); Memory::Write_U8(result_iter->ai_addrlen & 0xFF, sockoffset); Memory::Write_U8(result_iter->ai_addr->sa_family & 0xFF, sockoffset + 0x01); Memory::CopyToEmu(sockoffset + 0x2, result_iter->ai_addr->sa_data, sizeof(result_iter->ai_addr->sa_data)); sockoffset += 0x1C; } else { Memory::Write_U32(0, addr + 0x18); } if (result_iter->ai_next) { Memory::Write_U32(addr + WII_ADDR_INFO_SIZE, addr + 0x1C); } else { Memory::Write_U32(0, addr + 0x1C); } addr += WII_ADDR_INFO_SIZE; } freeaddrinfo(result); } else { // Host not found ret = -305; } request.Dump(GetDeviceName(), LogTypes::IOS_NET, LogTypes::LINFO); return GetDefaultReply(ret); }
// This is just for debugging / playing around. // There really is no reason to implement wd unless we can bend it such that // we can talk to the DS. IPCCommandResult NetWDCommand::IOCtlV(const IOCtlVRequest& request) { s32 return_value = IPC_SUCCESS; switch (request.request) { case IOCTLV_WD_SCAN: { // Gives parameters detailing type of scan and what to match // XXX - unused // ScanInfo *scan = (ScanInfo *)Memory::GetPointer(request.in_vectors.at(0).m_Address); u16* results = (u16*)Memory::GetPointer(request.io_vectors.at(0).address); // first u16 indicates number of BSSInfo following results[0] = Common::swap16(1); BSSInfo* bss = (BSSInfo*)&results[1]; memset(bss, 0, sizeof(BSSInfo)); bss->length = Common::swap16(sizeof(BSSInfo)); bss->rssi = Common::swap16(0xffff); for (int i = 0; i < BSSID_SIZE; ++i) bss->bssid[i] = i; const char* ssid = "dolphin-emu"; strcpy((char*)bss->ssid, ssid); bss->ssid_length = Common::swap16((u16)strlen(ssid)); bss->channel = Common::swap16(2); } break; case IOCTLV_WD_GET_INFO: { Info* info = (Info*)Memory::GetPointer(request.io_vectors.at(0).address); memset(info, 0, sizeof(Info)); // Probably used to disallow certain channels? memcpy(info->country, "US", 2); info->ntr_allowed_channels = Common::swap16(0xfffe); u8 address[Common::MAC_ADDRESS_SIZE]; GetMacAddress(address); memcpy(info->mac, address, sizeof(info->mac)); } break; case IOCTLV_WD_GET_MODE: case IOCTLV_WD_SET_LINKSTATE: case IOCTLV_WD_GET_LINKSTATE: case IOCTLV_WD_SET_CONFIG: case IOCTLV_WD_GET_CONFIG: case IOCTLV_WD_CHANGE_BEACON: case IOCTLV_WD_DISASSOC: case IOCTLV_WD_MP_SEND_FRAME: case IOCTLV_WD_SEND_FRAME: case IOCTLV_WD_CALL_WL: case IOCTLV_WD_MEASURE_CHANNEL: case IOCTLV_WD_GET_LASTERROR: case IOCTLV_WD_CHANGE_GAMEINFO: case IOCTLV_WD_CHANGE_VTSF: case IOCTLV_WD_RECV_FRAME: case IOCTLV_WD_RECV_NOTIFICATION: default: request.Dump(GetDeviceName(), LogTypes::IOS_NET, LogTypes::LINFO); } return GetDefaultReply(return_value); }