diff options
| -rw-r--r-- | src/citra_qt/debugger/wait_tree.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/client_session.cpp | 21 | ||||
| -rw-r--r-- | src/core/hle/kernel/server_session.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nwm/nwm_uds.cpp | 98 | 
4 files changed, 112 insertions, 10 deletions
diff --git a/src/citra_qt/debugger/wait_tree.h b/src/citra_qt/debugger/wait_tree.h index 06ef58ea7..2b38712b9 100644 --- a/src/citra_qt/debugger/wait_tree.h +++ b/src/citra_qt/debugger/wait_tree.h @@ -18,7 +18,6 @@ class WaitObject;  class Event;  class Mutex;  class Semaphore; -class Session;  class Thread;  class Timer;  } diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp index 6bc49ff64..fef97af1f 100644 --- a/src/core/hle/kernel/client_session.cpp +++ b/src/core/hle/kernel/client_session.cpp @@ -8,6 +8,7 @@  #include "core/hle/kernel/errors.h"  #include "core/hle/kernel/hle_ipc.h"  #include "core/hle/kernel/server_session.h" +#include "core/hle/kernel/session.h"  namespace Kernel { @@ -16,9 +17,13 @@ ClientSession::~ClientSession() {      // This destructor will be called automatically when the last ClientSession handle is closed by      // the emulated application. -    if (parent->server) { -        if (parent->server->hle_handler) -            parent->server->hle_handler->ClientDisconnected(parent->server); +    // Local references to ServerSession and SessionRequestHandler are necessary to guarantee they +    // will be kept alive until after ClientDisconnected() returns. +    SharedPtr<ServerSession> server = parent->server; +    if (server) { +        std::shared_ptr<SessionRequestHandler> hle_handler = server->hle_handler; +        if (hle_handler) +            hle_handler->ClientDisconnected(server);          // TODO(Subv): Force a wake up of all the ServerSession's waiting threads and set          // their WaitSynchronization result to 0xC920181A. @@ -28,11 +33,13 @@ ClientSession::~ClientSession() {  }  ResultCode ClientSession::SendSyncRequest() { -    // Signal the server session that new data is available -    if (parent->server) -        return parent->server->HandleSyncRequest(); +    // Keep ServerSession alive until we're done working with it. +    SharedPtr<ServerSession> server = parent->server; +    if (server == nullptr) +        return ERR_SESSION_CLOSED_BY_REMOTE; -    return ERR_SESSION_CLOSED_BY_REMOTE; +    // Signal the server session that new data is available +    return server->HandleSyncRequest();  }  } // namespace diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h index 28f365b9e..5365605da 100644 --- a/src/core/hle/kernel/server_session.h +++ b/src/core/hle/kernel/server_session.h @@ -9,7 +9,6 @@  #include "common/assert.h"  #include "common/common_types.h"  #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/session.h"  #include "core/hle/kernel/wait_object.h"  #include "core/hle/result.h"  #include "core/memory.h" @@ -19,6 +18,7 @@ namespace Kernel {  class ClientSession;  class ClientPort;  class ServerSession; +class Session;  class SessionRequestHandler;  class Thread; diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp index 084113188..6c4600f25 100644 --- a/src/core/hle/service/nwm/nwm_uds.cpp +++ b/src/core/hle/service/nwm/nwm_uds.cpp @@ -423,6 +423,102 @@ static void SetApplicationData(Interface* self) {      rb.Push(RESULT_SUCCESS);  } +/** + * NWM_UDS::DecryptBeaconData service function. + * Decrypts the encrypted data tags contained in the 802.11 beacons. + *  Inputs: + *      1 : Input network struct buffer descriptor. + *      2 : Input network struct buffer ptr. + *      3 : Input tag0 encrypted buffer descriptor. + *      4 : Input tag0 encrypted buffer ptr. + *      5 : Input tag1 encrypted buffer descriptor. + *      6 : Input tag1 encrypted buffer ptr. + *     64 : Output buffer descriptor. + *     65 : Output buffer ptr. + *  Outputs: + *      0 : Return header + *      1 : Result of function, 0 on success, otherwise error code + */ +static void DecryptBeaconData(Interface* self) { +    IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1F, 0, 6); + +    size_t desc_size; +    const VAddr network_struct_addr = rp.PopStaticBuffer(&desc_size); +    ASSERT(desc_size == sizeof(NetworkInfo)); + +    size_t data0_size; +    const VAddr encrypted_data0_addr = rp.PopStaticBuffer(&data0_size); + +    size_t data1_size; +    const VAddr encrypted_data1_addr = rp.PopStaticBuffer(&data1_size); + +    size_t output_buffer_size; +    const VAddr output_buffer_addr = rp.PeekStaticBuffer(0, &output_buffer_size); + +    // This size is hardcoded in the 3DS UDS code. +    ASSERT(output_buffer_size == sizeof(NodeInfo) * UDSMaxNodes); + +    LOG_WARNING(Service_NWM, "called in0=%08X in1=%08X out=%08X", encrypted_data0_addr, +                encrypted_data1_addr, output_buffer_addr); + +    NetworkInfo net_info; +    Memory::ReadBlock(network_struct_addr, &net_info, sizeof(net_info)); + +    // Read the encrypted data. +    // The first 4 bytes should be the OUI and the OUI Type of the tags. +    std::array<u8, 3> oui; +    Memory::ReadBlock(encrypted_data0_addr, oui.data(), oui.size()); +    ASSERT_MSG(oui == NintendoOUI, "Unexpected OUI"); +    Memory::ReadBlock(encrypted_data1_addr, oui.data(), oui.size()); +    ASSERT_MSG(oui == NintendoOUI, "Unexpected OUI"); + +    ASSERT_MSG(Memory::Read8(encrypted_data0_addr + 3) == +                   static_cast<u8>(NintendoTagId::EncryptedData0), +               "Unexpected tag id"); +    ASSERT_MSG(Memory::Read8(encrypted_data1_addr + 3) == +                   static_cast<u8>(NintendoTagId::EncryptedData1), +               "Unexpected tag id"); + +    std::vector<u8> beacon_data(data0_size + data1_size); +    Memory::ReadBlock(encrypted_data0_addr + 4, beacon_data.data(), data0_size); +    Memory::ReadBlock(encrypted_data1_addr + 4, beacon_data.data() + data0_size, data1_size); + +    // Decrypt the data +    DecryptBeaconData(net_info, beacon_data); + +    // The beacon data header contains the MD5 hash of the data. +    BeaconData beacon_header; +    std::memcpy(&beacon_header, beacon_data.data(), sizeof(beacon_header)); + +    // TODO(Subv): Verify the MD5 hash of the data and return 0xE1211005 if invalid. + +    u8 num_nodes = net_info.max_nodes; + +    std::vector<NodeInfo> nodes; + +    for (int i = 0; i < num_nodes; ++i) { +        BeaconNodeInfo info; +        std::memcpy(&info, beacon_data.data() + sizeof(beacon_header) + i * sizeof(info), +                    sizeof(info)); + +        // Deserialize the node information. +        NodeInfo node{}; +        node.friend_code_seed = info.friend_code_seed; +        node.network_node_id = info.network_node_id; +        for (int i = 0; i < info.username.size(); ++i) +            node.username[i] = info.username[i]; + +        nodes.push_back(node); +    } + +    Memory::ZeroBlock(output_buffer_addr, sizeof(NodeInfo) * UDSMaxNodes); +    Memory::WriteBlock(output_buffer_addr, nodes.data(), sizeof(NodeInfo) * nodes.size()); + +    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); +    rb.PushStaticBuffer(output_buffer_addr, output_buffer_size, 0); +    rb.Push(RESULT_SUCCESS); +} +  // Sends a 802.11 beacon frame with information about the current network.  static void BeaconBroadcastCallback(u64 userdata, int cycles_late) {      // Don't do anything if we're not actually hosting a network @@ -463,7 +559,7 @@ const Interface::FunctionInfo FunctionTable[] = {      {0x001B0302, InitializeWithVersion, "InitializeWithVersion"},      {0x001D0044, BeginHostingNetwork, "BeginHostingNetwork"},      {0x001E0084, nullptr, "ConnectToNetwork"}, -    {0x001F0006, nullptr, "DecryptBeaconData"}, +    {0x001F0006, DecryptBeaconData, "DecryptBeaconData"},      {0x00200040, nullptr, "Flush"},      {0x00210080, nullptr, "SetProbeResponseParam"},      {0x00220402, nullptr, "ScanOnConnection"},  | 
