diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp index bc68a9dc6..fd8169276 100644 --- a/src/core/hle/service/nwm/nwm_uds.cpp +++ b/src/core/hle/service/nwm/nwm_uds.cpp @@ -615,20 +615,14 @@ void NWM_UDS::RecvBeaconBroadcastData(Kernel::HLERequestContext& ctx) { out_buffer_size, wlan_comm_id, id, unk1, unk2, cur_buffer_size); } -void NWM_UDS::InitializeWithVersion(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x1B, 12, 2); - - u32 sharedmem_size = rp.Pop(); - - // Update the node information with the data the game gave us. - rp.PopRaw(current_node); - - u16 version = rp.Pop(); - - recv_buffer_memory = rp.PopObject(); +ResultVal> NWM_UDS::Initialize( + u32 sharedmem_size, const NodeInfo& node, u16 version, + Kernel::SharedPtr sharedmem) { + current_node = node; initialized = true; + recv_buffer_memory = std::move(sharedmem); ASSERT_MSG(recv_buffer_memory->GetSize() == sharedmem_size, "Invalid shared memory size."); if (auto room_member = Network::GetRoomMember().lock()) { @@ -650,14 +644,42 @@ void NWM_UDS::InitializeWithVersion(Kernel::HLERequestContext& ctx) { channel_data.clear(); } + return MakeResult(connection_status_event); +} + +void NWM_UDS::InitializeWithVersion(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1B, 12, 2); + u32 sharedmem_size = rp.Pop(); + auto node = rp.PopRaw(); + u16 version = rp.Pop(); + auto sharedmem = rp.PopObject(); + + auto result = Initialize(sharedmem_size, node, version, std::move(sharedmem)); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(RESULT_SUCCESS); - rb.PushCopyObjects(connection_status_event); + rb.Push(result.Code()); + rb.PushCopyObjects(result.ValueOr(nullptr)); LOG_DEBUG(Service_NWM, "called sharedmem_size=0x{:08X}, version=0x{:08X}", sharedmem_size, version); } +void NWM_UDS::InitializeDeprecated(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x01, 11, 2); + u32 sharedmem_size = rp.Pop(); + auto node = rp.PopRaw(); + auto sharedmem = rp.PopObject(); + + // The deprecated version uses fixed 0x100 as the version + auto result = Initialize(sharedmem_size, node, 0x100, std::move(sharedmem)); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + rb.Push(result.Code()); + rb.PushCopyObjects(result.ValueOr(nullptr)); + + LOG_DEBUG(Service_NWM, "called sharedmem_size=0x{:08X}", sharedmem_size); +} + void NWM_UDS::GetConnectionStatus(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0xB, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(13, 0); @@ -792,23 +814,14 @@ void NWM_UDS::Unbind(Kernel::HLERequestContext& ctx) { rb.Push(0); } -void NWM_UDS::BeginHostingNetwork(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x1D, 1, 4); - - const u32 passphrase_size = rp.Pop(); - - const std::vector network_info_buffer = rp.PopStaticBuffer(); - ASSERT(network_info_buffer.size() == sizeof(NetworkInfo)); - const std::vector passphrase = rp.PopStaticBuffer(); - ASSERT(passphrase.size() == passphrase_size); - +ResultCode NWM_UDS::BeginHostingNetwork(const u8* network_info_buffer, + std::size_t network_info_size, std::vector passphrase) { // TODO(Subv): Store the passphrase and verify it when attempting a connection. - LOG_DEBUG(Service_NWM, "called"); - { std::lock_guard lock(connection_status_mutex); - std::memcpy(&network_info, network_info_buffer.data(), sizeof(NetworkInfo)); + network_info = {}; + std::memcpy(&network_info, network_info_buffer, network_info_size); // The real UDS module throws a fatal error if this assert fails. ASSERT_MSG(network_info.max_nodes > 1, "Trying to host a network of only one member."); @@ -864,10 +877,45 @@ void NWM_UDS::BeginHostingNetwork(Kernel::HLERequestContext& ctx) { system.CoreTiming().ScheduleEvent(msToCycles(DefaultBeaconInterval * MillisecondsPerTU), beacon_broadcast_event, 0); + return RESULT_SUCCESS; +} + +void NWM_UDS::BeginHostingNetwork(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1D, 1, 4); + + const u32 passphrase_size = rp.Pop(); + + const std::vector network_info_buffer = rp.PopStaticBuffer(); + ASSERT(network_info_buffer.size() == sizeof(NetworkInfo)); + std::vector passphrase = rp.PopStaticBuffer(); + ASSERT(passphrase.size() == passphrase_size); + + LOG_DEBUG(Service_NWM, "called"); + auto result = BeginHostingNetwork(network_info_buffer.data(), network_info_buffer.size(), + std::move(passphrase)); LOG_DEBUG(Service_NWM, "An UDS network has been created."); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RESULT_SUCCESS); + rb.Push(result); +} + +void NWM_UDS::BeginHostingNetworkDeprecated(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x04, 0x10, 2); + // Real NWM module reads 0x108 bytes from the command buffer into the network info, where the + // last 0xCC bytes (application_data and size) are undefined values. Here we just read the first + // 0x3C defined bytes and zero application_data in BeginHostingNetwork. + const auto network_info_buffer = rp.PopRaw>(); + const u32 passphrase_size = rp.Pop(); + std::vector passphrase = rp.PopStaticBuffer(); + ASSERT(passphrase.size() == passphrase_size); + + LOG_DEBUG(Service_NWM, "called"); + auto result = BeginHostingNetwork(network_info_buffer.data(), network_info_buffer.size(), + std::move(passphrase)); + LOG_DEBUG(Service_NWM, "An UDS network has been created."); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(result); } void NWM_UDS::UpdateNetworkAttribute(Kernel::HLERequestContext& ctx) { @@ -1117,18 +1165,11 @@ void NWM_UDS::GetChannel(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NWM, "called"); } -void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x1E, 2, 4); - - u8 connection_type = rp.Pop(); - u32 passphrase_size = rp.Pop(); - - const std::vector network_struct_buffer = rp.PopStaticBuffer(); - ASSERT(network_struct_buffer.size() == sizeof(NetworkInfo)); - - const std::vector passphrase = rp.PopStaticBuffer(); - - std::memcpy(&network_info, network_struct_buffer.data(), sizeof(network_info)); +void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx, u16 command_id, + const u8* network_info_buffer, std::size_t network_info_size, + u8 connection_type, std::vector passphrase) { + network_info = {}; + std::memcpy(&network_info, network_info_buffer, network_info_size); // Start the connection sequence StartConnectionSequence(network_info.host_mac_address); @@ -1140,13 +1181,46 @@ void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx) { connection_event = ctx.SleepClientThread( system.Kernel().GetThreadManager().GetCurrentThread(), "uds::ConnectToNetwork", UDSConnectionTimeout, - [](Kernel::SharedPtr thread, Kernel::HLERequestContext& ctx, - Kernel::ThreadWakeupReason reason) { + [command_id](Kernel::SharedPtr thread, Kernel::HLERequestContext& ctx, + Kernel::ThreadWakeupReason reason) { // TODO(B3N30): Add error handling for host full and timeout - IPC::RequestBuilder rb(ctx, 0x1E, 1, 0); + IPC::RequestBuilder rb(ctx, command_id, 1, 0); rb.Push(RESULT_SUCCESS); LOG_DEBUG(Service_NWM, "connection sequence finished"); }); +} + +void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x1E, 2, 4); + + u8 connection_type = rp.Pop(); + u32 passphrase_size = rp.Pop(); + + const std::vector network_info_buffer = rp.PopStaticBuffer(); + ASSERT(network_info_buffer.size() == sizeof(NetworkInfo)); + + std::vector passphrase = rp.PopStaticBuffer(); + + ConnectToNetwork(ctx, 0x1E, network_info_buffer.data(), network_info_buffer.size(), + connection_type, std::move(passphrase)); + + LOG_DEBUG(Service_NWM, "called"); +} + +void NWM_UDS::ConnectToNetworkDeprecated(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x09, 0x11, 2); + + // Similar to BeginHostingNetworkDeprecated, we only read the first 0x3C bytes into the network + // info + const auto network_info_buffer = rp.PopRaw>(); + + u8 connection_type = rp.Pop(); + u32 passphrase_size = rp.Pop(); + + std::vector passphrase = rp.PopStaticBuffer(); + + ConnectToNetwork(ctx, 0x09, network_info_buffer.data(), network_info_buffer.size(), + connection_type, std::move(passphrase)); LOG_DEBUG(Service_NWM, "called"); } @@ -1175,8 +1249,8 @@ void NWM_UDS::SetApplicationData(Kernel::HLERequestContext& ctx) { rb.Push(RESULT_SUCCESS); } -void NWM_UDS::DecryptBeaconData(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x1F, 0, 6); +void NWM_UDS::DecryptBeaconData(Kernel::HLERequestContext& ctx, u16 command_id) { + IPC::RequestParser rp(ctx, command_id, 0, 6); const std::vector network_struct_buffer = rp.PopStaticBuffer(); ASSERT(network_struct_buffer.size() == sizeof(NetworkInfo)); @@ -1241,6 +1315,11 @@ void NWM_UDS::DecryptBeaconData(Kernel::HLERequestContext& ctx) { rb.PushStaticBuffer(output_buffer, 0); } +template +void NWM_UDS::DecryptBeaconData(Kernel::HLERequestContext& ctx) { + DecryptBeaconData(ctx, command_id); +} + // Sends a 802.11 beacon frame with information about the current network. void NWM_UDS::BeaconBroadcastCallback(u64 userdata, s64 cycles_late) { // Don't do anything if we're not actually hosting a network @@ -1266,19 +1345,19 @@ void NWM_UDS::BeaconBroadcastCallback(u64 userdata, s64 cycles_late) { NWM_UDS::NWM_UDS(Core::System& system) : ServiceFramework("nwm::UDS"), system(system) { static const FunctionInfo functions[] = { - {0x000102C2, nullptr, "Initialize (deprecated)"}, + {0x000102C2, &NWM_UDS::InitializeDeprecated, "Initialize (deprecated)"}, {0x00020000, nullptr, "Scrap"}, {0x00030000, &NWM_UDS::Shutdown, "Shutdown"}, - {0x00040402, nullptr, "CreateNetwork (deprecated)"}, + {0x00040402, &NWM_UDS::BeginHostingNetworkDeprecated, "BeginHostingNetwork (deprecated)"}, {0x00050040, nullptr, "EjectClient"}, {0x00060000, nullptr, "EjectSpectator"}, {0x00070080, &NWM_UDS::UpdateNetworkAttribute, "UpdateNetworkAttribute"}, {0x00080000, &NWM_UDS::DestroyNetwork, "DestroyNetwork"}, - {0x00090442, nullptr, "ConnectNetwork (deprecated)"}, + {0x00090442, &NWM_UDS::ConnectToNetworkDeprecated, "ConnectToNetwork (deprecated)"}, {0x000A0000, &NWM_UDS::DisconnectNetwork, "DisconnectNetwork"}, {0x000B0000, &NWM_UDS::GetConnectionStatus, "GetConnectionStatus"}, {0x000D0040, &NWM_UDS::GetNodeInformation, "GetNodeInformation"}, - {0x000E0006, nullptr, "DecryptBeaconData (deprecated)"}, + {0x000E0006, &NWM_UDS::DecryptBeaconData<0x0E>, "DecryptBeaconData (deprecated)"}, {0x000F0404, &NWM_UDS::RecvBeaconBroadcastData, "RecvBeaconBroadcastData"}, {0x00100042, &NWM_UDS::SetApplicationData, "SetApplicationData"}, {0x00110040, nullptr, "GetApplicationData"}, @@ -1291,7 +1370,7 @@ NWM_UDS::NWM_UDS(Core::System& system) : ServiceFramework("nwm::UDS"), system(sy {0x001B0302, &NWM_UDS::InitializeWithVersion, "InitializeWithVersion"}, {0x001D0044, &NWM_UDS::BeginHostingNetwork, "BeginHostingNetwork"}, {0x001E0084, &NWM_UDS::ConnectToNetwork, "ConnectToNetwork"}, - {0x001F0006, &NWM_UDS::DecryptBeaconData, "DecryptBeaconData"}, + {0x001F0006, &NWM_UDS::DecryptBeaconData<0x1F>, "DecryptBeaconData"}, {0x00200040, nullptr, "Flush"}, {0x00210080, nullptr, "SetProbeResponseParam"}, {0x00220402, nullptr, "ScanOnConnection"}, diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h index 3d7ef80d8..b28b578a7 100644 --- a/src/core/hle/service/nwm/nwm_uds.h +++ b/src/core/hle/service/nwm/nwm_uds.h @@ -320,6 +320,21 @@ private: */ void InitializeWithVersion(Kernel::HLERequestContext& ctx); + /** + * NWM_UDS::InitializeDeprecated service function + * Inputs: + * 1 : Shared memory size + * 2-11 : Input NodeInfo Structure + * 13 : Value 0 + * 14 : Shared memory handle + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Value 0 + * 3 : Output event handle + */ + void InitializeDeprecated(Kernel::HLERequestContext& ctx); + /** * NWM_UDS::BeginHostingNetwork service function. * Creates a network and starts broadcasting its presence. @@ -333,6 +348,19 @@ private: */ void BeginHostingNetwork(Kernel::HLERequestContext& ctx); + /** + * NWM_UDS::BeginHostingNetworkDeprecated service function. + * Creates a network and starts broadcasting its presence. + * Inputs: + * 1 - 15 : the NetworkInfo structure, excluding application data + * 16 : passphrase size + * 18 : VAddr of the passphrase. + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ + void BeginHostingNetworkDeprecated(Kernel::HLERequestContext& ctx); + /** * NWM_UDS::ConnectToNetwork service function. * This connects to the specified network @@ -350,6 +378,22 @@ private: */ void ConnectToNetwork(Kernel::HLERequestContext& ctx); + /** + * NWM_UDS::ConnectToNetwork Deprecatedservice function. + * This connects to the specified network + * Inputs: + * 0 : Command header + * 1 - 15 : the NetworkInfo structure, excluding application data + * 16 : Connection type: 0x1 = Client, 0x2 = Spectator. + * 17 : Passphrase buffer size + * 18 : (PassphraseSize<<12) | 2 + * 19 : Input passphrase buffer ptr + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ + void ConnectToNetworkDeprecated(Kernel::HLERequestContext& ctx); + /** * NWM_UDS::DecryptBeaconData service function. * Decrypts the encrypted data tags contained in the 802.11 beacons. @@ -367,8 +411,22 @@ private: * 1 : Result of function, 0 on success, otherwise error code * 2, 3: output buffer return descriptor & ptr */ + void DecryptBeaconData(Kernel::HLERequestContext& ctx, u16 command_id); + + template void DecryptBeaconData(Kernel::HLERequestContext& ctx); + ResultVal> Initialize( + u32 sharedmem_size, const NodeInfo& node, u16 version, + Kernel::SharedPtr sharedmem); + + ResultCode BeginHostingNetwork(const u8* network_info_buffer, std::size_t network_info_size, + std::vector passphrase); + + void ConnectToNetwork(Kernel::HLERequestContext& ctx, u16 command_id, + const u8* network_info_buffer, std::size_t network_info_size, + u8 connection_type, std::vector passphrase); + void BeaconBroadcastCallback(u64 userdata, s64 cycles_late); /**