mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Merge pull request #3070 from B3n30/uds_connect_disconnect
NWM_UDS: change to Service Framework
This commit is contained in:
		
						commit
						e2eab46535
					
				
					 7 changed files with 559 additions and 376 deletions
				
			
		|  | @ -21,7 +21,10 @@ void Init() { | ||||||
|     AddService(new NWM_SAP); |     AddService(new NWM_SAP); | ||||||
|     AddService(new NWM_SOC); |     AddService(new NWM_SOC); | ||||||
|     AddService(new NWM_TST); |     AddService(new NWM_TST); | ||||||
|     AddService(new NWM_UDS); | } | ||||||
|  | 
 | ||||||
|  | void InstallInterfaces(SM::ServiceManager& service_manager) { | ||||||
|  |     std::make_shared<NWM_UDS>()->InstallAsService(service_manager); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace NWM
 | } // namespace NWM
 | ||||||
|  |  | ||||||
|  | @ -4,11 +4,14 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include "core/hle/service/service.h" | ||||||
|  | 
 | ||||||
| namespace Service { | namespace Service { | ||||||
| namespace NWM { | namespace NWM { | ||||||
| 
 | 
 | ||||||
| /// Initialize all NWM services
 | /// Initialize all NWM services
 | ||||||
| void Init(); | void Init(); | ||||||
|  | void InstallInterfaces(SM::ServiceManager& service_manager); | ||||||
| 
 | 
 | ||||||
| } // namespace NWM
 | } // namespace NWM
 | ||||||
| } // namespace Service
 | } // namespace Service
 | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <cstring> | #include <cstring> | ||||||
| #include <list> | #include <list> | ||||||
|  | #include <map> | ||||||
| #include <mutex> | #include <mutex> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
| #include <vector> | #include <vector> | ||||||
|  | @ -31,6 +32,7 @@ namespace NWM { | ||||||
| namespace ErrCodes { | namespace ErrCodes { | ||||||
| enum { | enum { | ||||||
|     NotInitialized = 2, |     NotInitialized = 2, | ||||||
|  |     WrongStatus = 490, | ||||||
| }; | }; | ||||||
| } // namespace ErrCodes
 | } // namespace ErrCodes
 | ||||||
| 
 | 
 | ||||||
|  | @ -75,13 +77,21 @@ static u8 network_channel = DefaultNetworkChannel; | ||||||
| // Information about the network that we're currently connected to.
 | // Information about the network that we're currently connected to.
 | ||||||
| static NetworkInfo network_info; | static NetworkInfo network_info; | ||||||
| 
 | 
 | ||||||
|  | // Mapping of mac addresses to their respective node_ids.
 | ||||||
|  | static std::map<MacAddress, u32> node_map; | ||||||
|  | 
 | ||||||
| // Event that will generate and send the 802.11 beacon frames.
 | // Event that will generate and send the 802.11 beacon frames.
 | ||||||
| static CoreTiming::EventType* beacon_broadcast_event; | static CoreTiming::EventType* beacon_broadcast_event; | ||||||
| 
 | 
 | ||||||
|  | // Callback identifier for the OnWifiPacketReceived event.
 | ||||||
|  | static Network::RoomMember::CallbackHandle<Network::WifiPacket> wifi_packet_received; | ||||||
|  | 
 | ||||||
| // Mutex to synchronize access to the connection status between the emulation thread and the
 | // Mutex to synchronize access to the connection status between the emulation thread and the
 | ||||||
| // network thread.
 | // network thread.
 | ||||||
| static std::mutex connection_status_mutex; | static std::mutex connection_status_mutex; | ||||||
| 
 | 
 | ||||||
|  | static Kernel::SharedPtr<Kernel::Event> connection_event; | ||||||
|  | 
 | ||||||
| // Mutex to synchronize access to the list of received beacons between the emulation thread and the
 | // Mutex to synchronize access to the list of received beacons between the emulation thread and the
 | ||||||
| // network thread.
 | // network thread.
 | ||||||
| static std::mutex beacon_mutex; | static std::mutex beacon_mutex; | ||||||
|  | @ -119,7 +129,12 @@ std::list<Network::WifiPacket> GetReceivedBeacons(const MacAddress& sender) { | ||||||
| 
 | 
 | ||||||
| /// Sends a WifiPacket to the room we're currently connected to.
 | /// Sends a WifiPacket to the room we're currently connected to.
 | ||||||
| void SendPacket(Network::WifiPacket& packet) { | void SendPacket(Network::WifiPacket& packet) { | ||||||
|     // TODO(Subv): Implement.
 |     if (auto room_member = Network::GetRoomMember().lock()) { | ||||||
|  |         if (room_member->GetState() == Network::RoomMember::State::Joined) { | ||||||
|  |             packet.transmitter_address = room_member->GetMacAddress(); | ||||||
|  |             room_member->SendWifiPacket(packet); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -214,6 +229,8 @@ static void HandleEAPoLPacket(const Network::WifiPacket& packet) { | ||||||
| 
 | 
 | ||||||
|         network_info.total_nodes++; |         network_info.total_nodes++; | ||||||
| 
 | 
 | ||||||
|  |         node_map[packet.transmitter_address] = node_id; | ||||||
|  | 
 | ||||||
|         // Send the EAPoL-Logoff packet.
 |         // Send the EAPoL-Logoff packet.
 | ||||||
|         using Network::WifiPacket; |         using Network::WifiPacket; | ||||||
|         WifiPacket eapol_logoff; |         WifiPacket eapol_logoff; | ||||||
|  | @ -237,6 +254,7 @@ static void HandleEAPoLPacket(const Network::WifiPacket& packet) { | ||||||
|         } |         } | ||||||
|         auto logoff = ParseEAPoLLogoffFrame(packet.data); |         auto logoff = ParseEAPoLLogoffFrame(packet.data); | ||||||
| 
 | 
 | ||||||
|  |         network_info.host_mac_address = packet.transmitter_address; | ||||||
|         network_info.total_nodes = logoff.connected_nodes; |         network_info.total_nodes = logoff.connected_nodes; | ||||||
|         network_info.max_nodes = logoff.max_nodes; |         network_info.max_nodes = logoff.max_nodes; | ||||||
| 
 | 
 | ||||||
|  | @ -260,6 +278,7 @@ static void HandleEAPoLPacket(const Network::WifiPacket& packet) { | ||||||
|         // If blocking is implemented this lock needs to be changed,
 |         // If blocking is implemented this lock needs to be changed,
 | ||||||
|         // otherwise it might cause deadlocks
 |         // otherwise it might cause deadlocks
 | ||||||
|         connection_status_event->Signal(); |         connection_status_event->Signal(); | ||||||
|  |         connection_event->Signal(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -397,6 +416,35 @@ void HandleAuthenticationFrame(const Network::WifiPacket& packet) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Handles the deauthentication frames sent from clients to hosts, when they leave a session
 | ||||||
|  | void HandleDeauthenticationFrame(const Network::WifiPacket& packet) { | ||||||
|  |     LOG_DEBUG(Service_NWM, "called"); | ||||||
|  |     std::unique_lock<std::recursive_mutex> hle_lock(HLE::g_hle_lock, std::defer_lock); | ||||||
|  |     std::unique_lock<std::mutex> lock(connection_status_mutex, std::defer_lock); | ||||||
|  |     std::lock(hle_lock, lock); | ||||||
|  |     if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost)) { | ||||||
|  |         LOG_ERROR(Service_NWM, "Got deauthentication frame but we are not the host"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     if (node_map.find(packet.transmitter_address) == node_map.end()) { | ||||||
|  |         LOG_ERROR(Service_NWM, "Got deauthentication frame from unknown node"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     u16 node_id = node_map[packet.transmitter_address]; | ||||||
|  |     auto node = std::find_if(node_info.begin(), node_info.end(), [&node_id](const NodeInfo& info) { | ||||||
|  |         return info.network_node_id == node_id + 1; | ||||||
|  |     }); | ||||||
|  |     ASSERT(node != node_info.end()); | ||||||
|  | 
 | ||||||
|  |     connection_status.node_bitmask &= ~(1 << node_id); | ||||||
|  |     connection_status.changed_nodes |= 1 << node_id; | ||||||
|  |     connection_status.total_nodes--; | ||||||
|  | 
 | ||||||
|  |     network_info.total_nodes--; | ||||||
|  |     connection_status_event->Signal(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void HandleDataFrame(const Network::WifiPacket& packet) { | static void HandleDataFrame(const Network::WifiPacket& packet) { | ||||||
|     switch (GetFrameEtherType(packet.data)) { |     switch (GetFrameEtherType(packet.data)) { | ||||||
|     case EtherType::EAPoL: |     case EtherType::EAPoL: | ||||||
|  | @ -423,47 +471,32 @@ void OnWifiPacketReceived(const Network::WifiPacket& packet) { | ||||||
|     case Network::WifiPacket::PacketType::Data: |     case Network::WifiPacket::PacketType::Data: | ||||||
|         HandleDataFrame(packet); |         HandleDataFrame(packet); | ||||||
|         break; |         break; | ||||||
|  |     case Network::WifiPacket::PacketType::Deauthentication: | ||||||
|  |         HandleDeauthenticationFrame(packet); | ||||||
|  |         break; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::Shutdown(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::Shutdown service function |     IPC::RequestParser rp(ctx, 0x03, 0, 0); | ||||||
|  *  Inputs: |  | ||||||
|  *      1 : None |  | ||||||
|  *  Outputs: |  | ||||||
|  *      0 : Return header |  | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |  | ||||||
|  */ |  | ||||||
| static void Shutdown(Interface* self) { |  | ||||||
|     u32* cmd_buff = Kernel::GetCommandBuffer(); |  | ||||||
| 
 | 
 | ||||||
|     // TODO(purpasmart): Verify return header on HW
 |     if (auto room_member = Network::GetRoomMember().lock()) | ||||||
|  |         room_member->Unbind(wifi_packet_received); | ||||||
| 
 | 
 | ||||||
|     cmd_buff[1] = RESULT_SUCCESS.raw; |     for (auto bind_node : channel_data) { | ||||||
|  |         bind_node.second.event->Signal(); | ||||||
|  |     } | ||||||
|  |     channel_data.clear(); | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_NWM, "(STUBBED) called"); |     recv_buffer_memory.reset(); | ||||||
|  | 
 | ||||||
|  |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  |     rb.Push(RESULT_SUCCESS); | ||||||
|  |     LOG_DEBUG(Service_NWM, "called"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::RecvBeaconBroadcastData(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::RecvBeaconBroadcastData service function |     IPC::RequestParser rp(ctx, 0x0F, 16, 4); | ||||||
|  * Returns the raw beacon data for nearby networks that match the supplied WlanCommId. |  | ||||||
|  *  Inputs: |  | ||||||
|  *      1 : Output buffer max size |  | ||||||
|  *    2-3 : Unknown |  | ||||||
|  *    4-5 : Host MAC address. |  | ||||||
|  *   6-14 : Unused |  | ||||||
|  *     15 : WLan Comm Id |  | ||||||
|  *     16 : Id |  | ||||||
|  *     17 : Value 0 |  | ||||||
|  *     18 : Input handle |  | ||||||
|  *     19 : (Size<<4) | 12 |  | ||||||
|  *     20 : Output buffer ptr |  | ||||||
|  *  Outputs: |  | ||||||
|  *      0 : Return header |  | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |  | ||||||
|  */ |  | ||||||
| static void RecvBeaconBroadcastData(Interface* self) { |  | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0F, 16, 4); |  | ||||||
| 
 | 
 | ||||||
|     u32 out_buffer_size = rp.Pop<u32>(); |     u32 out_buffer_size = rp.Pop<u32>(); | ||||||
|     u32 unk1 = rp.Pop<u32>(); |     u32 unk1 = rp.Pop<u32>(); | ||||||
|  | @ -476,14 +509,16 @@ static void RecvBeaconBroadcastData(Interface* self) { | ||||||
| 
 | 
 | ||||||
|     u32 wlan_comm_id = rp.Pop<u32>(); |     u32 wlan_comm_id = rp.Pop<u32>(); | ||||||
|     u32 id = rp.Pop<u32>(); |     u32 id = rp.Pop<u32>(); | ||||||
|     Kernel::Handle input_handle = rp.PopHandle(); |     // From 3dbrew:
 | ||||||
|  |     // 'Official user processes create a new event handle which is then passed to this command.
 | ||||||
|  |     // However, those user processes don't save that handle anywhere afterwards.'
 | ||||||
|  |     // So we don't save/use that event too.
 | ||||||
|  |     Kernel::SharedPtr<Kernel::Event> input_event = rp.PopObject<Kernel::Event>(); | ||||||
| 
 | 
 | ||||||
|     size_t desc_size; |     Kernel::MappedBuffer out_buffer = rp.PopMappedBuffer(); | ||||||
|     const VAddr out_buffer_ptr = rp.PopMappedBuffer(&desc_size); |     ASSERT(out_buffer.GetSize() == out_buffer_size); | ||||||
|     ASSERT(desc_size == out_buffer_size); |  | ||||||
| 
 | 
 | ||||||
|     VAddr current_buffer_pos = out_buffer_ptr; |     size_t cur_buffer_size = sizeof(BeaconDataReplyHeader); | ||||||
|     u32 total_size = sizeof(BeaconDataReplyHeader); |  | ||||||
| 
 | 
 | ||||||
|     // Retrieve all beacon frames that were received from the desired mac address.
 |     // Retrieve all beacon frames that were received from the desired mac address.
 | ||||||
|     auto beacons = GetReceivedBeacons(mac_address); |     auto beacons = GetReceivedBeacons(mac_address); | ||||||
|  | @ -492,9 +527,6 @@ static void RecvBeaconBroadcastData(Interface* self) { | ||||||
|     data_reply_header.total_entries = static_cast<u32>(beacons.size()); |     data_reply_header.total_entries = static_cast<u32>(beacons.size()); | ||||||
|     data_reply_header.max_output_size = out_buffer_size; |     data_reply_header.max_output_size = out_buffer_size; | ||||||
| 
 | 
 | ||||||
|     Memory::WriteBlock(current_buffer_pos, &data_reply_header, sizeof(BeaconDataReplyHeader)); |  | ||||||
|     current_buffer_pos += sizeof(BeaconDataReplyHeader); |  | ||||||
| 
 |  | ||||||
|     // Write each of the received beacons into the buffer
 |     // Write each of the received beacons into the buffer
 | ||||||
|     for (const auto& beacon : beacons) { |     for (const auto& beacon : beacons) { | ||||||
|         BeaconEntryHeader entry{}; |         BeaconEntryHeader entry{}; | ||||||
|  | @ -505,45 +537,30 @@ static void RecvBeaconBroadcastData(Interface* self) { | ||||||
|         entry.header_size = sizeof(BeaconEntryHeader); |         entry.header_size = sizeof(BeaconEntryHeader); | ||||||
|         entry.mac_address = beacon.transmitter_address; |         entry.mac_address = beacon.transmitter_address; | ||||||
| 
 | 
 | ||||||
|         ASSERT(current_buffer_pos < out_buffer_ptr + out_buffer_size); |         ASSERT(cur_buffer_size < out_buffer_size); | ||||||
| 
 | 
 | ||||||
|         Memory::WriteBlock(current_buffer_pos, &entry, sizeof(BeaconEntryHeader)); |         out_buffer.Write(&entry, cur_buffer_size, sizeof(BeaconEntryHeader)); | ||||||
|         current_buffer_pos += sizeof(BeaconEntryHeader); |         cur_buffer_size += sizeof(BeaconEntryHeader); | ||||||
| 
 |         const unsigned char* beacon_data = beacon.data.data(); | ||||||
|         Memory::WriteBlock(current_buffer_pos, beacon.data.data(), beacon.data.size()); |         out_buffer.Write(beacon_data, cur_buffer_size, beacon.data.size()); | ||||||
|         current_buffer_pos += static_cast<VAddr>(beacon.data.size()); |         cur_buffer_size += beacon.data.size(); | ||||||
| 
 |  | ||||||
|         total_size += static_cast<u32>(sizeof(BeaconEntryHeader) + beacon.data.size()); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Update the total size in the structure and write it to the buffer again.
 |     // Update the total size in the structure and write it to the buffer again.
 | ||||||
|     data_reply_header.total_size = total_size; |     data_reply_header.total_size = cur_buffer_size; | ||||||
|     Memory::WriteBlock(out_buffer_ptr, &data_reply_header, sizeof(BeaconDataReplyHeader)); |     out_buffer.Write(&data_reply_header, 0, sizeof(BeaconDataReplyHeader)); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 1); | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|  |     rb.PushMappedBuffer(out_buffer); | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_NWM, "called out_buffer_size=0x%08X, wlan_comm_id=0x%08X, id=0x%08X," |     LOG_DEBUG(Service_NWM, "called out_buffer_size=0x%08X, wlan_comm_id=0x%08X, id=0x%08X," | ||||||
|                            "input_handle=0x%08X, out_buffer_ptr=0x%08X, unk1=0x%08X, unk2=0x%08X", |                            "unk1=0x%08X, unk2=0x%08X, offset=%zu", | ||||||
|               out_buffer_size, wlan_comm_id, id, input_handle, out_buffer_ptr, unk1, unk2); |               out_buffer_size, wlan_comm_id, id, unk1, unk2, cur_buffer_size); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::InitializeWithVersion(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::Initialize service function |     IPC::RequestParser rp(ctx, 0x1B, 12, 2); | ||||||
|  *  Inputs: |  | ||||||
|  *      1 : Shared memory size |  | ||||||
|  *   2-11 : Input NodeInfo Structure |  | ||||||
|  *     12 : 2-byte Version |  | ||||||
|  *     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 |  | ||||||
|  */ |  | ||||||
| static void InitializeWithVersion(Interface* self) { |  | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1B, 12, 2); |  | ||||||
| 
 | 
 | ||||||
|     u32 sharedmem_size = rp.Pop<u32>(); |     u32 sharedmem_size = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|  | @ -552,14 +569,18 @@ static void InitializeWithVersion(Interface* self) { | ||||||
| 
 | 
 | ||||||
|     u16 version = rp.Pop<u16>(); |     u16 version = rp.Pop<u16>(); | ||||||
| 
 | 
 | ||||||
|     Kernel::Handle sharedmem_handle = rp.PopHandle(); |     recv_buffer_memory = rp.PopObject<Kernel::SharedMemory>(); | ||||||
| 
 |  | ||||||
|     recv_buffer_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(sharedmem_handle); |  | ||||||
| 
 | 
 | ||||||
|     initialized = true; |     initialized = true; | ||||||
| 
 | 
 | ||||||
|     ASSERT_MSG(recv_buffer_memory->size == sharedmem_size, "Invalid shared memory size."); |     ASSERT_MSG(recv_buffer_memory->size == sharedmem_size, "Invalid shared memory size."); | ||||||
| 
 | 
 | ||||||
|  |     if (auto room_member = Network::GetRoomMember().lock()) { | ||||||
|  |         wifi_packet_received = room_member->BindOnWifiPacketReceived(OnWifiPacketReceived); | ||||||
|  |     } else { | ||||||
|  |         LOG_ERROR(Service_NWM, "Network isn't initalized"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     { |     { | ||||||
|         std::lock_guard<std::mutex> lock(connection_status_mutex); |         std::lock_guard<std::mutex> lock(connection_status_mutex); | ||||||
| 
 | 
 | ||||||
|  | @ -567,33 +588,19 @@ static void InitializeWithVersion(Interface* self) { | ||||||
|         // except for the actual status value.
 |         // except for the actual status value.
 | ||||||
|         connection_status = {}; |         connection_status = {}; | ||||||
|         connection_status.status = static_cast<u32>(NetworkStatus::NotConnected); |         connection_status.status = static_cast<u32>(NetworkStatus::NotConnected); | ||||||
|  |         node_info.clear(); | ||||||
|  |         node_info.push_back(current_node); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|     rb.PushCopyHandles(Kernel::g_handle_table.Create(connection_status_event).Unwrap()); |     rb.PushCopyObjects(connection_status_event); | ||||||
| 
 | 
 | ||||||
|     // TODO(Subv): Connect the OnWifiPacketReceived function to the wifi packet received callback of
 |     LOG_DEBUG(Service_NWM, "called sharedmem_size=0x%08X, version=0x%08X", sharedmem_size, version); | ||||||
|     // the room we're currently in.
 |  | ||||||
| 
 |  | ||||||
|     LOG_DEBUG(Service_NWM, "called sharedmem_size=0x%08X, version=0x%08X, sharedmem_handle=0x%08X", |  | ||||||
|               sharedmem_size, version, sharedmem_handle); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::GetConnectionStatus(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::GetConnectionStatus service function. |     IPC::RequestParser rp(ctx, 0xB, 0, 0); | ||||||
|  * Returns the connection status structure for the currently open network connection. |  | ||||||
|  * This structure contains information about the connection, |  | ||||||
|  * like the number of connected nodes, etc. |  | ||||||
|  *  Inputs: |  | ||||||
|  *      0 : Command header. |  | ||||||
|  *  Outputs: |  | ||||||
|  *      0 : Return header |  | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |  | ||||||
|  *      2-13 : Channel of the current WiFi network connection. |  | ||||||
|  */ |  | ||||||
| static void GetConnectionStatus(Interface* self) { |  | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xB, 0, 0); |  | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(13, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(13, 0); | ||||||
| 
 | 
 | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|  | @ -611,19 +618,8 @@ static void GetConnectionStatus(Interface* self) { | ||||||
|     LOG_DEBUG(Service_NWM, "called"); |     LOG_DEBUG(Service_NWM, "called"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::GetNodeInformation(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::GetNodeInformation service function. |     IPC::RequestParser rp(ctx, 0xD, 1, 0); | ||||||
|  * Returns the node inforamtion structure for the currently connected node. |  | ||||||
|  *  Inputs: |  | ||||||
|  *      0 : Command header. |  | ||||||
|  *      1 : Node ID. |  | ||||||
|  *  Outputs: |  | ||||||
|  *      0 : Return header |  | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |  | ||||||
|  *      2-11 : NodeInfo structure. |  | ||||||
|  */ |  | ||||||
| static void GetNodeInformation(Interface* self) { |  | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0xD, 1, 0); |  | ||||||
|     u16 network_node_id = rp.Pop<u16>(); |     u16 network_node_id = rp.Pop<u16>(); | ||||||
| 
 | 
 | ||||||
|     if (!initialized) { |     if (!initialized) { | ||||||
|  | @ -653,22 +649,8 @@ static void GetNodeInformation(Interface* self) { | ||||||
|     LOG_DEBUG(Service_NWM, "called"); |     LOG_DEBUG(Service_NWM, "called"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::Bind(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::Bind service function. |     IPC::RequestParser rp(ctx, 0x12, 4, 0); | ||||||
|  * Binds a BindNodeId to a data channel and retrieves a data event. |  | ||||||
|  *  Inputs: |  | ||||||
|  *      1 : BindNodeId |  | ||||||
|  *      2 : Receive buffer size. |  | ||||||
|  *      3 : u8 Data channel to bind to. |  | ||||||
|  *      4 : Network node id. |  | ||||||
|  *  Outputs: |  | ||||||
|  *      0 : Return header |  | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |  | ||||||
|  *      2 : Copy handle descriptor. |  | ||||||
|  *      3 : Data available event handle. |  | ||||||
|  */ |  | ||||||
| static void Bind(Interface* self) { |  | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x12, 4, 0); |  | ||||||
| 
 | 
 | ||||||
|     u32 bind_node_id = rp.Pop<u32>(); |     u32 bind_node_id = rp.Pop<u32>(); | ||||||
|     u32 recv_buffer_size = rp.Pop<u32>(); |     u32 recv_buffer_size = rp.Pop<u32>(); | ||||||
|  | @ -681,6 +663,8 @@ static void Bind(Interface* self) { | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|         rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::UDS, |         rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::UDS, | ||||||
|                            ErrorSummary::WrongArgument, ErrorLevel::Usage)); |                            ErrorSummary::WrongArgument, ErrorLevel::Usage)); | ||||||
|  |         LOG_WARNING(Service_NWM, "data_channel = %d, bind_node_id = %d", data_channel, | ||||||
|  |                     bind_node_id); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -689,6 +673,7 @@ static void Bind(Interface* self) { | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|         rb.Push(ResultCode(ErrorDescription::OutOfMemory, ErrorModule::UDS, |         rb.Push(ResultCode(ErrorDescription::OutOfMemory, ErrorModule::UDS, | ||||||
|                            ErrorSummary::OutOfResource, ErrorLevel::Status)); |                            ErrorSummary::OutOfResource, ErrorLevel::Status)); | ||||||
|  |         LOG_WARNING(Service_NWM, "max bind nodes"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -697,6 +682,7 @@ static void Bind(Interface* self) { | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|         rb.Push(ResultCode(ErrorDescription::TooLarge, ErrorModule::UDS, |         rb.Push(ResultCode(ErrorDescription::TooLarge, ErrorModule::UDS, | ||||||
|                            ErrorSummary::WrongArgument, ErrorLevel::Usage)); |                            ErrorSummary::WrongArgument, ErrorLevel::Usage)); | ||||||
|  |         LOG_WARNING(Service_NWM, "MinRecvBufferSize"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -711,20 +697,11 @@ static void Bind(Interface* self) { | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|     rb.PushCopyHandles(Kernel::g_handle_table.Create(event).Unwrap()); |     rb.PushCopyObjects(event); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::Unbind(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::Unbind service function. |     IPC::RequestParser rp(ctx, 0x12, 1, 0); | ||||||
|  * Unbinds a BindNodeId from a data channel. |  | ||||||
|  *  Inputs: |  | ||||||
|  *      1 : BindNodeId |  | ||||||
|  *  Outputs: |  | ||||||
|  *      0 : Return header |  | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |  | ||||||
|  */ |  | ||||||
| static void Unbind(Interface* self) { |  | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x12, 1, 0); |  | ||||||
| 
 | 
 | ||||||
|     u32 bind_node_id = rp.Pop<u32>(); |     u32 bind_node_id = rp.Pop<u32>(); | ||||||
|     if (bind_node_id == 0) { |     if (bind_node_id == 0) { | ||||||
|  | @ -754,27 +731,15 @@ static void Unbind(Interface* self) { | ||||||
|     rb.Push<u32>(0); |     rb.Push<u32>(0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::BeginHostingNetwork(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::BeginHostingNetwork service function. |     IPC::RequestParser rp(ctx, 0x1D, 1, 4); | ||||||
|  * Creates a network and starts broadcasting its presence. |  | ||||||
|  *  Inputs: |  | ||||||
|  *      1 : Passphrase buffer size. |  | ||||||
|  *      3 : VAddr of the NetworkInfo structure. |  | ||||||
|  *      5 : VAddr of the passphrase. |  | ||||||
|  *  Outputs: |  | ||||||
|  *      0 : Return header |  | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |  | ||||||
|  */ |  | ||||||
| static void BeginHostingNetwork(Interface* self) { |  | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1D, 1, 4); |  | ||||||
| 
 | 
 | ||||||
|     const u32 passphrase_size = rp.Pop<u32>(); |     const u32 passphrase_size = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     size_t desc_size; |     const std::vector<u8> network_info_buffer = rp.PopStaticBuffer(); | ||||||
|     const VAddr network_info_address = rp.PopStaticBuffer(&desc_size); |     ASSERT(network_info_buffer.size() == sizeof(NetworkInfo)); | ||||||
|     ASSERT(desc_size == sizeof(NetworkInfo)); |     const std::vector<u8> passphrase = rp.PopStaticBuffer(); | ||||||
|     const VAddr passphrase_address = rp.PopStaticBuffer(&desc_size); |     ASSERT(passphrase.size() == passphrase_size); | ||||||
|     ASSERT(desc_size == passphrase_size); |  | ||||||
| 
 | 
 | ||||||
|     // TODO(Subv): Store the passphrase and verify it when attempting a connection.
 |     // TODO(Subv): Store the passphrase and verify it when attempting a connection.
 | ||||||
| 
 | 
 | ||||||
|  | @ -782,8 +747,7 @@ static void BeginHostingNetwork(Interface* self) { | ||||||
| 
 | 
 | ||||||
|     { |     { | ||||||
|         std::lock_guard<std::mutex> lock(connection_status_mutex); |         std::lock_guard<std::mutex> lock(connection_status_mutex); | ||||||
| 
 |         std::memcpy(&network_info, network_info_buffer.data(), sizeof(NetworkInfo)); | ||||||
|         Memory::ReadBlock(network_info_address, &network_info, sizeof(NetworkInfo)); |  | ||||||
| 
 | 
 | ||||||
|         // The real UDS module throws a fatal error if this assert fails.
 |         // 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."); |         ASSERT_MSG(network_info.max_nodes > 1, "Trying to host a network of only one member."); | ||||||
|  | @ -845,59 +809,94 @@ static void BeginHostingNetwork(Interface* self) { | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::UpdateNetworkAttribute(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::DestroyNetwork service function. |     IPC::RequestParser rp(ctx, 0x07, 2, 0); | ||||||
|  * Closes the network that we're currently hosting. |     rp.Skip(2, false); | ||||||
|  *  Inputs: |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  *      0 : Command header. |     rb.Push(RESULT_SUCCESS); | ||||||
|  *  Outputs: | } | ||||||
|  *      0 : Return header |  | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |  | ||||||
|  */ |  | ||||||
| static void DestroyNetwork(Interface* self) { |  | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x08, 0, 0); |  | ||||||
| 
 | 
 | ||||||
|     // TODO(Subv): Find out what happens if this is called while
 | void NWM_UDS::DestroyNetwork(Kernel::HLERequestContext& ctx) { | ||||||
|     // no network is being hosted.
 |     IPC::RequestParser rp(ctx, 0x08, 0, 0); | ||||||
| 
 | 
 | ||||||
|     // Unschedule the beacon broadcast event.
 |     // Unschedule the beacon broadcast event.
 | ||||||
|     CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0); |     CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0); | ||||||
| 
 | 
 | ||||||
|     { |     // Only a host can destroy
 | ||||||
|     std::lock_guard<std::mutex> lock(connection_status_mutex); |     std::lock_guard<std::mutex> lock(connection_status_mutex); | ||||||
| 
 |     if (connection_status.status != static_cast<u8>(NetworkStatus::ConnectedAsHost)) { | ||||||
|         // TODO(Subv): Check if connection_status is indeed reset after this call.
 |         IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|         connection_status = {}; |         rb.Push(ResultCode(ErrCodes::WrongStatus, ErrorModule::UDS, ErrorSummary::InvalidState, | ||||||
|         connection_status.status = static_cast<u8>(NetworkStatus::NotConnected); |                            ErrorLevel::Status)); | ||||||
|  |         LOG_WARNING(Service_NWM, "called with status %u", connection_status.status); | ||||||
|  |         return; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     // TODO(B3N30): Send 3 Deauth packets
 | ||||||
|  | 
 | ||||||
|  |     u16_le tmp_node_id = connection_status.network_node_id; | ||||||
|  |     connection_status = {}; | ||||||
|  |     connection_status.status = static_cast<u32>(NetworkStatus::NotConnected); | ||||||
|  |     connection_status.network_node_id = tmp_node_id; | ||||||
|     connection_status_event->Signal(); |     connection_status_event->Signal(); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
| 
 | 
 | ||||||
|  |     for (auto bind_node : channel_data) { | ||||||
|  |         bind_node.second.event->Signal(); | ||||||
|  |     } | ||||||
|  |     channel_data.clear(); | ||||||
|  | 
 | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
| 
 | 
 | ||||||
|     LOG_WARNING(Service_NWM, "called"); |     LOG_DEBUG(Service_NWM, "called"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::DisconnectNetwork(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::SendTo service function. |     IPC::RequestParser rp(ctx, 0xA, 0, 0); | ||||||
|  * Sends a data frame to the UDS network we're connected to. |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|  *  Inputs: | 
 | ||||||
|  *      0 : Command header. |     using Network::WifiPacket; | ||||||
|  *      1 : Unknown. |     WifiPacket deauth; | ||||||
|  *      2 : u16 Destination network node id. |     { | ||||||
|  *      3 : u8 Data channel. |         std::lock_guard<std::mutex> lock(connection_status_mutex); | ||||||
|  *      4 : Buffer size >> 2 |         if (connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost)) { | ||||||
|  *      5 : Data size |             // A real 3ds makes strange things here. We do the same
 | ||||||
|  *      6 : Flags |             u16_le tmp_node_id = connection_status.network_node_id; | ||||||
|  *      7 : Input buffer descriptor |             connection_status = {}; | ||||||
|  *      8 : Input buffer address |             connection_status.status = static_cast<u32>(NetworkStatus::ConnectedAsHost); | ||||||
|  *  Outputs: |             connection_status.network_node_id = tmp_node_id; | ||||||
|  *      0 : Return header |             LOG_DEBUG(Service_NWM, "called as a host"); | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |             rb.Push(ResultCode(ErrCodes::WrongStatus, ErrorModule::UDS, ErrorSummary::InvalidState, | ||||||
|  */ |                                ErrorLevel::Status)); | ||||||
| static void SendTo(Interface* self) { |             return; | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x17, 6, 2); |         } | ||||||
|  |         u16_le tmp_node_id = connection_status.network_node_id; | ||||||
|  |         connection_status = {}; | ||||||
|  |         connection_status.status = static_cast<u32>(NetworkStatus::NotConnected); | ||||||
|  |         connection_status.network_node_id = tmp_node_id; | ||||||
|  |         connection_status_event->Signal(); | ||||||
|  | 
 | ||||||
|  |         deauth.channel = network_channel; | ||||||
|  |         // TODO(B3N30): Add disconnect reason
 | ||||||
|  |         deauth.data = {}; | ||||||
|  |         deauth.destination_address = network_info.host_mac_address; | ||||||
|  |         deauth.type = WifiPacket::PacketType::Deauthentication; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     SendPacket(deauth); | ||||||
|  | 
 | ||||||
|  |     for (auto bind_node : channel_data) { | ||||||
|  |         bind_node.second.event->Signal(); | ||||||
|  |     } | ||||||
|  |     channel_data.clear(); | ||||||
|  | 
 | ||||||
|  |     rb.Push(RESULT_SUCCESS); | ||||||
|  |     LOG_DEBUG(Service_NWM, "called"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NWM_UDS::SendTo(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx, 0x17, 6, 2); | ||||||
| 
 | 
 | ||||||
|     rp.Skip(1, false); |     rp.Skip(1, false); | ||||||
|     u16 dest_node_id = rp.Pop<u16>(); |     u16 dest_node_id = rp.Pop<u16>(); | ||||||
|  | @ -906,9 +905,9 @@ static void SendTo(Interface* self) { | ||||||
|     u32 data_size = rp.Pop<u32>(); |     u32 data_size = rp.Pop<u32>(); | ||||||
|     u32 flags = rp.Pop<u32>(); |     u32 flags = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     size_t desc_size; |     std::vector<u8> input_buffer = rp.PopStaticBuffer(); | ||||||
|     const VAddr input_address = rp.PopStaticBuffer(&desc_size); |     ASSERT(input_buffer.size() >= data_size); | ||||||
|     ASSERT(desc_size >= data_size); |     input_buffer.resize(data_size); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
| 
 | 
 | ||||||
|  | @ -935,13 +934,11 @@ static void SendTo(Interface* self) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::vector<u8> data(data_size); |  | ||||||
|     Memory::ReadBlock(input_address, data.data(), data.size()); |  | ||||||
| 
 |  | ||||||
|     // TODO(B3N30): Increment the sequence number after each sent packet.
 |     // TODO(B3N30): Increment the sequence number after each sent packet.
 | ||||||
|     u16 sequence_number = 0; |     u16 sequence_number = 0; | ||||||
|     std::vector<u8> data_payload = GenerateDataPayload( |     std::vector<u8> data_payload = | ||||||
|         data, data_channel, dest_node_id, connection_status.network_node_id, sequence_number); |         GenerateDataPayload(input_buffer, data_channel, dest_node_id, | ||||||
|  |                             connection_status.network_node_id, sequence_number); | ||||||
| 
 | 
 | ||||||
|     // TODO(B3N30): Retrieve the MAC address of the dest_node_id and our own to encrypt
 |     // TODO(B3N30): Retrieve the MAC address of the dest_node_id and our own to encrypt
 | ||||||
|     // and encapsulate the payload.
 |     // and encapsulate the payload.
 | ||||||
|  | @ -962,34 +959,15 @@ static void SendTo(Interface* self) { | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::PullPacket(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::PullPacket service function. |     IPC::RequestParser rp(ctx, 0x14, 3, 0); | ||||||
|  * Receives a data frame from the specified bind node id |  | ||||||
|  *  Inputs: |  | ||||||
|  *      0 : Command header. |  | ||||||
|  *      1 : Bind node id. |  | ||||||
|  *      2 : Max out buff size >> 2. |  | ||||||
|  *      3 : Max out buff size. |  | ||||||
|  *     64 : Output buffer descriptor |  | ||||||
|  *     65 : Output buffer address |  | ||||||
|  *  Outputs: |  | ||||||
|  *      0 : Return header |  | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |  | ||||||
|  *      2 : Received data size |  | ||||||
|  *      3 : u16 Source network node id |  | ||||||
|  *      4 : Buffer descriptor |  | ||||||
|  *      5 : Buffer address |  | ||||||
|  */ |  | ||||||
| static void PullPacket(Interface* self) { |  | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x14, 3, 0); |  | ||||||
| 
 | 
 | ||||||
|     u32 bind_node_id = rp.Pop<u32>(); |     u32 bind_node_id = rp.Pop<u32>(); | ||||||
|     u32 max_out_buff_size_aligned = rp.Pop<u32>(); |     u32 max_out_buff_size_aligned = rp.Pop<u32>(); | ||||||
|     u32 max_out_buff_size = rp.Pop<u32>(); |     u32 max_out_buff_size = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     size_t desc_size; |     // This size is hard coded into the uds module. We don't know the meaning yet.
 | ||||||
|     const VAddr output_address = rp.PeekStaticBuffer(0, &desc_size); |     u32 buff_size = std::min<u32>(max_out_buff_size_aligned, 0x172) << 2; | ||||||
|     ASSERT(desc_size == max_out_buff_size); |  | ||||||
| 
 | 
 | ||||||
|     std::lock_guard<std::mutex> lock(connection_status_mutex); |     std::lock_guard<std::mutex> lock(connection_status_mutex); | ||||||
|     if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost) && |     if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost) && | ||||||
|  | @ -1014,12 +992,12 @@ static void PullPacket(Interface* self) { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (channel->second.received_packets.empty()) { |     if (channel->second.received_packets.empty()) { | ||||||
|         Memory::ZeroBlock(output_address, desc_size); |         std::vector<u8> output_buffer(buff_size, 0); | ||||||
|         IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); |         IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); | ||||||
|         rb.Push(RESULT_SUCCESS); |         rb.Push(RESULT_SUCCESS); | ||||||
|         rb.Push<u32>(0); |         rb.Push<u32>(0); | ||||||
|         rb.Push<u16>(0); |         rb.Push<u16>(0); | ||||||
|         rb.PushStaticBuffer(output_address, desc_size, 0); |         rb.PushStaticBuffer(output_buffer, 0); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -1036,32 +1014,22 @@ static void PullPacket(Interface* self) { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); |     IPC::RequestBuilder rb = rp.MakeBuilder(3, 2); | ||||||
|     Memory::ZeroBlock(output_address, desc_size); | 
 | ||||||
|  |     std::vector<u8> output_buffer(buff_size, 0); | ||||||
|     // Write the actual data.
 |     // Write the actual data.
 | ||||||
|     Memory::WriteBlock(output_address, |     std::memcpy(output_buffer.data(), | ||||||
|                        next_packet.data() + sizeof(LLCHeader) + sizeof(SecureDataHeader), |                 next_packet.data() + sizeof(LLCHeader) + sizeof(SecureDataHeader), data_size); | ||||||
|                        data_size); |  | ||||||
| 
 | 
 | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|     rb.Push<u32>(data_size); |     rb.Push<u32>(data_size); | ||||||
|     rb.Push<u16>(secure_data.src_node_id); |     rb.Push<u16>(secure_data.src_node_id); | ||||||
|     rb.PushStaticBuffer(output_address, desc_size, 0); |     rb.PushStaticBuffer(output_buffer, 0); | ||||||
| 
 | 
 | ||||||
|     channel->second.received_packets.pop_front(); |     channel->second.received_packets.pop_front(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::GetChannel(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::GetChannel service function. |     IPC::RequestParser rp(ctx, 0x1A, 0, 0); | ||||||
|  * Returns the WiFi channel in which the network we're connected to is transmitting. |  | ||||||
|  *  Inputs: |  | ||||||
|  *      0 : Command header. |  | ||||||
|  *  Outputs: |  | ||||||
|  *      0 : Return header |  | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |  | ||||||
|  *      2 : Channel of the current WiFi network connection. |  | ||||||
|  */ |  | ||||||
| static void GetChannel(Interface* self) { |  | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1A, 0, 0); |  | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); | ||||||
| 
 | 
 | ||||||
|     std::lock_guard<std::mutex> lock(connection_status_mutex); |     std::lock_guard<std::mutex> lock(connection_status_mutex); | ||||||
|  | @ -1075,26 +1043,46 @@ static void GetChannel(Interface* self) { | ||||||
|     LOG_DEBUG(Service_NWM, "called"); |     LOG_DEBUG(Service_NWM, "called"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::ConnectToNetwork(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::SetApplicationData service function. |     IPC::RequestParser rp(ctx, 0x1E, 2, 4); | ||||||
|  * Updates the application data that is being broadcast in the beacon frames | 
 | ||||||
|  * for the network that we're hosting. |     u8 connection_type = rp.Pop<u8>(); | ||||||
|  *  Inputs: |     u32 passphrase_size = rp.Pop<u32>(); | ||||||
|  *      1 : Data size. | 
 | ||||||
|  *      3 : VAddr of the data. |     const std::vector<u8> network_struct_buffer = rp.PopStaticBuffer(); | ||||||
|  *  Outputs: |     ASSERT(network_struct_buffer.size() == sizeof(NetworkInfo)); | ||||||
|  *      0 : Return header | 
 | ||||||
|  *      1 : Result of function, 0 on success, otherwise error code |     const std::vector<u8> passphrase = rp.PopStaticBuffer(); | ||||||
|  *      2 : Channel of the current WiFi network connection. | 
 | ||||||
|  */ |     std::memcpy(&network_info, network_struct_buffer.data(), sizeof(network_info)); | ||||||
| static void SetApplicationData(Interface* self) { | 
 | ||||||
|     IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1A, 1, 2); |     // Start the connection sequence
 | ||||||
|  |     StartConnectionSequence(network_info.host_mac_address); | ||||||
|  | 
 | ||||||
|  |     // 300 ms
 | ||||||
|  |     // Since this timing is handled by core_timing it could differ from the 'real world' time
 | ||||||
|  |     static constexpr std::chrono::nanoseconds UDSConnectionTimeout{300000000}; | ||||||
|  | 
 | ||||||
|  |     connection_event = ctx.SleepClientThread( | ||||||
|  |         Kernel::GetCurrentThread(), "uds::ConnectToNetwork", UDSConnectionTimeout, | ||||||
|  |         [](Kernel::SharedPtr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, | ||||||
|  |            ThreadWakeupReason reason) { | ||||||
|  |             // TODO(B3N30): Add error handling for host full and timeout
 | ||||||
|  |             IPC::RequestBuilder rb(ctx, 0x1E, 1, 0); | ||||||
|  |             rb.Push(RESULT_SUCCESS); | ||||||
|  |             LOG_DEBUG(Service_NWM, "connection sequence finished"); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     LOG_DEBUG(Service_NWM, "called"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void NWM_UDS::SetApplicationData(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx, 0x10, 1, 2); | ||||||
| 
 | 
 | ||||||
|     u32 size = rp.Pop<u32>(); |     u32 size = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     size_t desc_size; |     const std::vector<u8> application_data = rp.PopStaticBuffer(); | ||||||
|     const VAddr address = rp.PopStaticBuffer(&desc_size); |     ASSERT(application_data.size() == size); | ||||||
|     ASSERT(desc_size == size); |  | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_NWM, "called"); |     LOG_DEBUG(Service_NWM, "called"); | ||||||
| 
 | 
 | ||||||
|  | @ -1107,73 +1095,43 @@ static void SetApplicationData(Interface* self) { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     network_info.application_data_size = size; |     network_info.application_data_size = size; | ||||||
|     Memory::ReadBlock(address, network_info.application_data.data(), size); |     std::memcpy(network_info.application_data.data(), application_data.data(), size); | ||||||
| 
 | 
 | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | void NWM_UDS::DecryptBeaconData(Kernel::HLERequestContext& ctx) { | ||||||
|  * NWM_UDS::DecryptBeaconData service function. |     IPC::RequestParser rp(ctx, 0x1F, 0, 6); | ||||||
|  * 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 std::vector<u8> network_struct_buffer = rp.PopStaticBuffer(); | ||||||
|     const VAddr network_struct_addr = rp.PopStaticBuffer(&desc_size); |     ASSERT(network_struct_buffer.size() == sizeof(NetworkInfo)); | ||||||
|     ASSERT(desc_size == sizeof(NetworkInfo)); |  | ||||||
| 
 | 
 | ||||||
|     size_t data0_size; |     const std::vector<u8> encrypted_data0_buffer = rp.PopStaticBuffer(); | ||||||
|     const VAddr encrypted_data0_addr = rp.PopStaticBuffer(&data0_size); |     const std::vector<u8> encrypted_data1_buffer = rp.PopStaticBuffer(); | ||||||
| 
 | 
 | ||||||
|     size_t data1_size; |     LOG_DEBUG(Service_NWM, "called"); | ||||||
|     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; |     NetworkInfo net_info; | ||||||
|     Memory::ReadBlock(network_struct_addr, &net_info, sizeof(net_info)); |     std::memcpy(&net_info, network_struct_buffer.data(), sizeof(net_info)); | ||||||
| 
 | 
 | ||||||
|     // Read the encrypted data.
 |     // Read the encrypted data.
 | ||||||
|     // The first 4 bytes should be the OUI and the OUI Type of the tags.
 |     // The first 4 bytes should be the OUI and the OUI Type of the tags.
 | ||||||
|     std::array<u8, 3> oui; |     std::array<u8, 3> oui; | ||||||
|     Memory::ReadBlock(encrypted_data0_addr, oui.data(), oui.size()); |     std::memcpy(oui.data(), encrypted_data0_buffer.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(oui == NintendoOUI, "Unexpected OUI"); | ||||||
| 
 | 
 | ||||||
|     ASSERT_MSG(Memory::Read8(encrypted_data0_addr + 3) == |     ASSERT_MSG(encrypted_data0_buffer[3] == static_cast<u8>(NintendoTagId::EncryptedData0), | ||||||
|                    static_cast<u8>(NintendoTagId::EncryptedData0), |  | ||||||
|                "Unexpected tag id"); |  | ||||||
|     ASSERT_MSG(Memory::Read8(encrypted_data1_addr + 3) == |  | ||||||
|                    static_cast<u8>(NintendoTagId::EncryptedData1), |  | ||||||
|                "Unexpected tag id"); |                "Unexpected tag id"); | ||||||
| 
 | 
 | ||||||
|     std::vector<u8> beacon_data(data0_size + data1_size); |     std::vector<u8> beacon_data(encrypted_data0_buffer.size() - 4 + encrypted_data1_buffer.size() - | ||||||
|     Memory::ReadBlock(encrypted_data0_addr + 4, beacon_data.data(), data0_size); |                                 4); | ||||||
|     Memory::ReadBlock(encrypted_data1_addr + 4, beacon_data.data() + data0_size, data1_size); |     std::memcpy(beacon_data.data(), encrypted_data0_buffer.data() + 4, | ||||||
|  |                 encrypted_data0_buffer.size() - 4); | ||||||
|  |     std::memcpy(beacon_data.data() + encrypted_data0_buffer.size() - 4, | ||||||
|  |                 encrypted_data1_buffer.data() + 4, encrypted_data1_buffer.size() - 4); | ||||||
| 
 | 
 | ||||||
|     // Decrypt the data
 |     // Decrypt the data
 | ||||||
|     DecryptBeaconData(net_info, beacon_data); |     DecryptBeacon(net_info, beacon_data); | ||||||
| 
 | 
 | ||||||
|     // The beacon data header contains the MD5 hash of the data.
 |     // The beacon data header contains the MD5 hash of the data.
 | ||||||
|     BeaconData beacon_header; |     BeaconData beacon_header; | ||||||
|  | @ -1200,12 +1158,12 @@ static void DecryptBeaconData(Interface* self) { | ||||||
|         nodes.push_back(node); |         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); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||||
|     rb.PushStaticBuffer(output_buffer_addr, output_buffer_size, 0); |  | ||||||
|     rb.Push(RESULT_SUCCESS); |     rb.Push(RESULT_SUCCESS); | ||||||
|  | 
 | ||||||
|  |     std::vector<u8> output_buffer(sizeof(NodeInfo) * UDSMaxNodes, 0); | ||||||
|  |     std::memcpy(output_buffer.data(), nodes.data(), sizeof(NodeInfo) * nodes.size()); | ||||||
|  |     rb.PushStaticBuffer(output_buffer, 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Sends a 802.11 beacon frame with information about the current network.
 | // Sends a 802.11 beacon frame with information about the current network.
 | ||||||
|  | @ -1230,63 +1188,42 @@ static void BeaconBroadcastCallback(u64 userdata, int cycles_late) { | ||||||
|                               beacon_broadcast_event, 0); |                               beacon_broadcast_event, 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | NWM_UDS::NWM_UDS() : ServiceFramework("nwm::UDS") { | ||||||
|  * Called when a client connects to an UDS network we're hosting, |     static const FunctionInfo functions[] = { | ||||||
|  * updates the connection status and signals the update event. |  | ||||||
|  * @param network_node_id Network Node Id of the connecting client. |  | ||||||
|  */ |  | ||||||
| void OnClientConnected(u16 network_node_id) { |  | ||||||
|     std::lock_guard<std::mutex> lock(connection_status_mutex); |  | ||||||
|     ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost), |  | ||||||
|                "Can not accept clients if we're not hosting a network"); |  | ||||||
|     ASSERT_MSG(connection_status.total_nodes < connection_status.max_nodes, |  | ||||||
|                "Can not accept connections on a full network"); |  | ||||||
| 
 |  | ||||||
|     u32 node_id = GetNextAvailableNodeId(); |  | ||||||
|     connection_status.node_bitmask |= 1 << node_id; |  | ||||||
|     connection_status.changed_nodes |= 1 << node_id; |  | ||||||
|     connection_status.nodes[node_id] = network_node_id; |  | ||||||
|     connection_status.total_nodes++; |  | ||||||
|     connection_status_event->Signal(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const Interface::FunctionInfo FunctionTable[] = { |  | ||||||
|         {0x000102C2, nullptr, "Initialize (deprecated)"}, |         {0x000102C2, nullptr, "Initialize (deprecated)"}, | ||||||
|         {0x00020000, nullptr, "Scrap"}, |         {0x00020000, nullptr, "Scrap"}, | ||||||
|     {0x00030000, Shutdown, "Shutdown"}, |         {0x00030000, &NWM_UDS::Shutdown, "Shutdown"}, | ||||||
|         {0x00040402, nullptr, "CreateNetwork (deprecated)"}, |         {0x00040402, nullptr, "CreateNetwork (deprecated)"}, | ||||||
|         {0x00050040, nullptr, "EjectClient"}, |         {0x00050040, nullptr, "EjectClient"}, | ||||||
|         {0x00060000, nullptr, "EjectSpectator"}, |         {0x00060000, nullptr, "EjectSpectator"}, | ||||||
|     {0x00070080, nullptr, "UpdateNetworkAttribute"}, |         {0x00070080, &NWM_UDS::UpdateNetworkAttribute, "UpdateNetworkAttribute"}, | ||||||
|     {0x00080000, DestroyNetwork, "DestroyNetwork"}, |         {0x00080000, &NWM_UDS::DestroyNetwork, "DestroyNetwork"}, | ||||||
|         {0x00090442, nullptr, "ConnectNetwork (deprecated)"}, |         {0x00090442, nullptr, "ConnectNetwork (deprecated)"}, | ||||||
|     {0x000A0000, nullptr, "DisconnectNetwork"}, |         {0x000A0000, &NWM_UDS::DisconnectNetwork, "DisconnectNetwork"}, | ||||||
|     {0x000B0000, GetConnectionStatus, "GetConnectionStatus"}, |         {0x000B0000, &NWM_UDS::GetConnectionStatus, "GetConnectionStatus"}, | ||||||
|     {0x000D0040, GetNodeInformation, "GetNodeInformation"}, |         {0x000D0040, &NWM_UDS::GetNodeInformation, "GetNodeInformation"}, | ||||||
|         {0x000E0006, nullptr, "DecryptBeaconData (deprecated)"}, |         {0x000E0006, nullptr, "DecryptBeaconData (deprecated)"}, | ||||||
|     {0x000F0404, RecvBeaconBroadcastData, "RecvBeaconBroadcastData"}, |         {0x000F0404, &NWM_UDS::RecvBeaconBroadcastData, "RecvBeaconBroadcastData"}, | ||||||
|     {0x00100042, SetApplicationData, "SetApplicationData"}, |         {0x00100042, &NWM_UDS::SetApplicationData, "SetApplicationData"}, | ||||||
|         {0x00110040, nullptr, "GetApplicationData"}, |         {0x00110040, nullptr, "GetApplicationData"}, | ||||||
|     {0x00120100, Bind, "Bind"}, |         {0x00120100, &NWM_UDS::Bind, "Bind"}, | ||||||
|     {0x00130040, Unbind, "Unbind"}, |         {0x00130040, &NWM_UDS::Unbind, "Unbind"}, | ||||||
|     {0x001400C0, PullPacket, "PullPacket"}, |         {0x001400C0, &NWM_UDS::PullPacket, "PullPacket"}, | ||||||
|         {0x00150080, nullptr, "SetMaxSendDelay"}, |         {0x00150080, nullptr, "SetMaxSendDelay"}, | ||||||
|     {0x00170182, SendTo, "SendTo"}, |         {0x00170182, &NWM_UDS::SendTo, "SendTo"}, | ||||||
|     {0x001A0000, GetChannel, "GetChannel"}, |         {0x001A0000, &NWM_UDS::GetChannel, "GetChannel"}, | ||||||
|     {0x001B0302, InitializeWithVersion, "InitializeWithVersion"}, |         {0x001B0302, &NWM_UDS::InitializeWithVersion, "InitializeWithVersion"}, | ||||||
|     {0x001D0044, BeginHostingNetwork, "BeginHostingNetwork"}, |         {0x001D0044, &NWM_UDS::BeginHostingNetwork, "BeginHostingNetwork"}, | ||||||
|     {0x001E0084, nullptr, "ConnectToNetwork"}, |         {0x001E0084, &NWM_UDS::ConnectToNetwork, "ConnectToNetwork"}, | ||||||
|     {0x001F0006, DecryptBeaconData, "DecryptBeaconData"}, |         {0x001F0006, &NWM_UDS::DecryptBeaconData, "DecryptBeaconData"}, | ||||||
|         {0x00200040, nullptr, "Flush"}, |         {0x00200040, nullptr, "Flush"}, | ||||||
|         {0x00210080, nullptr, "SetProbeResponseParam"}, |         {0x00210080, nullptr, "SetProbeResponseParam"}, | ||||||
|         {0x00220402, nullptr, "ScanOnConnection"}, |         {0x00220402, nullptr, "ScanOnConnection"}, | ||||||
| }; |     }; | ||||||
| 
 |  | ||||||
| NWM_UDS::NWM_UDS() { |  | ||||||
|     connection_status_event = |     connection_status_event = | ||||||
|         Kernel::Event::Create(Kernel::ResetType::OneShot, "NWM::connection_status_event"); |         Kernel::Event::Create(Kernel::ResetType::OneShot, "NWM::connection_status_event"); | ||||||
| 
 | 
 | ||||||
|     Register(FunctionTable); |     RegisterHandlers(functions); | ||||||
| 
 | 
 | ||||||
|     beacon_broadcast_event = |     beacon_broadcast_event = | ||||||
|         CoreTiming::RegisterEvent("UDS::BeaconBroadcastCallback", BeaconBroadcastCallback); |         CoreTiming::RegisterEvent("UDS::BeaconBroadcastCallback", BeaconBroadcastCallback); | ||||||
|  | @ -1305,6 +1242,9 @@ NWM_UDS::~NWM_UDS() { | ||||||
|         connection_status.status = static_cast<u32>(NetworkStatus::NotConnected); |         connection_status.status = static_cast<u32>(NetworkStatus::NotConnected); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (auto room_member = Network::GetRoomMember().lock()) | ||||||
|  |         room_member->Unbind(wifi_packet_received); | ||||||
|  | 
 | ||||||
|     CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0); |     CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -97,14 +97,250 @@ enum class TagId : u8 { | ||||||
|     VendorSpecific = 221 |     VendorSpecific = 221 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class NWM_UDS final : public Interface { | class NWM_UDS final : public ServiceFramework<NWM_UDS> { | ||||||
| public: | public: | ||||||
|     NWM_UDS(); |     NWM_UDS(); | ||||||
|     ~NWM_UDS() override; |     ~NWM_UDS(); | ||||||
| 
 | 
 | ||||||
|     std::string GetPortName() const override { | private: | ||||||
|         return "nwm::UDS"; |     void UpdateNetworkAttribute(Kernel::HLERequestContext& ctx); | ||||||
|     } | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::Shutdown service function | ||||||
|  |      *  Inputs: | ||||||
|  |      *      1 : None | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     void Shutdown(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::DestroyNetwork service function. | ||||||
|  |      * Closes the network that we're currently hosting. | ||||||
|  |      *  Inputs: | ||||||
|  |      *      0 : Command header. | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     void DestroyNetwork(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::DisconnectNetwork service function. | ||||||
|  |      * This disconnects this device from the network. | ||||||
|  |      *  Inputs: | ||||||
|  |      *      0 : Command header. | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     void DisconnectNetwork(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::GetConnectionStatus service function. | ||||||
|  |      * Returns the connection status structure for the currently open network connection. | ||||||
|  |      * This structure contains information about the connection, | ||||||
|  |      * like the number of connected nodes, etc. | ||||||
|  |      *  Inputs: | ||||||
|  |      *      0 : Command header. | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      *      2-13 : Channel of the current WiFi network connection. | ||||||
|  |      */ | ||||||
|  |     void GetConnectionStatus(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::GetNodeInformation service function. | ||||||
|  |      * Returns the node inforamtion structure for the currently connected node. | ||||||
|  |      *  Inputs: | ||||||
|  |      *      0 : Command header. | ||||||
|  |      *      1 : Node ID. | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      *      2-11 : NodeInfo structure. | ||||||
|  |      */ | ||||||
|  |     void GetNodeInformation(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::RecvBeaconBroadcastData service function | ||||||
|  |      * Returns the raw beacon data for nearby networks that match the supplied WlanCommId. | ||||||
|  |      *  Inputs: | ||||||
|  |      *      1 : Output buffer max size | ||||||
|  |      *    2-3 : Unknown | ||||||
|  |      *    4-5 : Host MAC address. | ||||||
|  |      *   6-14 : Unused | ||||||
|  |      *     15 : WLan Comm Id | ||||||
|  |      *     16 : Id | ||||||
|  |      *     17 : Value 0 | ||||||
|  |      *     18 : Input handle | ||||||
|  |      *     19 : (Size<<4) | 12 | ||||||
|  |      *     20 : Output buffer ptr | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      *      2, 3: output buffer return descriptor & ptr | ||||||
|  |      */ | ||||||
|  |     void RecvBeaconBroadcastData(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::SetApplicationData service function. | ||||||
|  |      * Updates the application data that is being broadcast in the beacon frames | ||||||
|  |      * for the network that we're hosting. | ||||||
|  |      *  Inputs: | ||||||
|  |      *      1 : Data size. | ||||||
|  |      *      3 : VAddr of the data. | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      *      2 : Channel of the current WiFi network connection. | ||||||
|  |      */ | ||||||
|  |     void SetApplicationData(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::Bind service function. | ||||||
|  |      * Binds a BindNodeId to a data channel and retrieves a data event. | ||||||
|  |      *  Inputs: | ||||||
|  |      *      1 : BindNodeId | ||||||
|  |      *      2 : Receive buffer size. | ||||||
|  |      *      3 : u8 Data channel to bind to. | ||||||
|  |      *      4 : Network node id. | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      *      2 : Copy handle descriptor. | ||||||
|  |      *      3 : Data available event handle. | ||||||
|  |      */ | ||||||
|  |     void Bind(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::Unbind service function. | ||||||
|  |      * Unbinds a BindNodeId from a data channel. | ||||||
|  |      *  Inputs: | ||||||
|  |      *      1 : BindNodeId | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     void Unbind(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::PullPacket service function. | ||||||
|  |      * Receives a data frame from the specified bind node id | ||||||
|  |      *  Inputs: | ||||||
|  |      *      0 : Command header. | ||||||
|  |      *      1 : Bind node id. | ||||||
|  |      *      2 : Max out buff size >> 2. | ||||||
|  |      *      3 : Max out buff size. | ||||||
|  |      *     64 : Output buffer descriptor | ||||||
|  |      *     65 : Output buffer address | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      *      2 : Received data size | ||||||
|  |      *      3 : u16 Source network node id | ||||||
|  |      *      4 : Buffer descriptor | ||||||
|  |      *      5 : Buffer address | ||||||
|  |      */ | ||||||
|  |     void PullPacket(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::SendTo service function. | ||||||
|  |      * Sends a data frame to the UDS network we're connected to. | ||||||
|  |      *  Inputs: | ||||||
|  |      *      0 : Command header. | ||||||
|  |      *      1 : Unknown. | ||||||
|  |      *      2 : u16 Destination network node id. | ||||||
|  |      *      3 : u8 Data channel. | ||||||
|  |      *      4 : Buffer size >> 2 | ||||||
|  |      *      5 : Data size | ||||||
|  |      *      6 : Flags | ||||||
|  |      *      7 : Input buffer descriptor | ||||||
|  |      *      8 : Input buffer address | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     void SendTo(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::GetChannel service function. | ||||||
|  |      * Returns the WiFi channel in which the network we're connected to is transmitting. | ||||||
|  |      *  Inputs: | ||||||
|  |      *      0 : Command header. | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      *      2 : Channel of the current WiFi network connection. | ||||||
|  |      */ | ||||||
|  |     void GetChannel(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::Initialize service function | ||||||
|  |      *  Inputs: | ||||||
|  |      *      1 : Shared memory size | ||||||
|  |      *   2-11 : Input NodeInfo Structure | ||||||
|  |      *     12 : 2-byte Version | ||||||
|  |      *     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 InitializeWithVersion(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::BeginHostingNetwork service function. | ||||||
|  |      * Creates a network and starts broadcasting its presence. | ||||||
|  |      *  Inputs: | ||||||
|  |      *      1 : Passphrase buffer size. | ||||||
|  |      *      3 : VAddr of the NetworkInfo structure. | ||||||
|  |      *      5 : VAddr of the passphrase. | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     void BeginHostingNetwork(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * NWM_UDS::ConnectToNetwork service function. | ||||||
|  |      * This connects to the specified network | ||||||
|  |      *  Inputs: | ||||||
|  |      *      0 : Command header | ||||||
|  |      *      1 : Connection type: 0x1 = Client, 0x2 = Spectator. | ||||||
|  |      *      2 : Passphrase buffer size | ||||||
|  |      *      3 : (NetworkStructSize<<12) | 0x402 | ||||||
|  |      *      4 : Network struct buffer ptr | ||||||
|  |      *      5 : (PassphraseSize<<12) | 2 | ||||||
|  |      *      6 : Input passphrase buffer ptr | ||||||
|  |      *  Outputs: | ||||||
|  |      *      0 : Return header | ||||||
|  |      *      1 : Result of function, 0 on success, otherwise error code | ||||||
|  |      */ | ||||||
|  |     void ConnectToNetwork(Kernel::HLERequestContext& ctx); | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * 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 | ||||||
|  |      *      2, 3: output buffer return descriptor & ptr | ||||||
|  |      */ | ||||||
|  |     void DecryptBeaconData(Kernel::HLERequestContext& ctx); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace NWM
 | } // namespace NWM
 | ||||||
|  |  | ||||||
|  | @ -224,7 +224,7 @@ std::vector<u8> GeneratedEncryptedData(const NetworkInfo& network_info, const No | ||||||
|     return buffer; |     return buffer; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DecryptBeaconData(const NetworkInfo& network_info, std::vector<u8>& buffer) { | void DecryptBeacon(const NetworkInfo& network_info, std::vector<u8>& buffer) { | ||||||
|     // Decrypt the data using AES-CTR and the NWM beacon key.
 |     // Decrypt the data using AES-CTR and the NWM beacon key.
 | ||||||
|     using CryptoPP::AES; |     using CryptoPP::AES; | ||||||
|     std::array<u8, AES::BLOCKSIZE> counter = GetBeaconCryptoCTR(network_info); |     std::array<u8, AES::BLOCKSIZE> counter = GetBeaconCryptoCTR(network_info); | ||||||
|  |  | ||||||
|  | @ -127,7 +127,7 @@ static_assert(sizeof(BeaconData) == 0x12, "BeaconData has incorrect size."); | ||||||
| /**
 | /**
 | ||||||
|  * Decrypts the beacon data buffer for the network described by `network_info`. |  * Decrypts the beacon data buffer for the network described by `network_info`. | ||||||
|  */ |  */ | ||||||
| void DecryptBeaconData(const NetworkInfo& network_info, std::vector<u8>& buffer); | void DecryptBeacon(const NetworkInfo& network_info, std::vector<u8>& buffer); | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Generates an 802.11 beacon frame starting at the management frame header. |  * Generates an 802.11 beacon frame starting at the management frame header. | ||||||
|  |  | ||||||
|  | @ -273,6 +273,7 @@ void Init() { | ||||||
|     AC::InstallInterfaces(*SM::g_service_manager); |     AC::InstallInterfaces(*SM::g_service_manager); | ||||||
|     LDR::InstallInterfaces(*SM::g_service_manager); |     LDR::InstallInterfaces(*SM::g_service_manager); | ||||||
|     MIC::InstallInterfaces(*SM::g_service_manager); |     MIC::InstallInterfaces(*SM::g_service_manager); | ||||||
|  |     NWM::InstallInterfaces(*SM::g_service_manager); | ||||||
| 
 | 
 | ||||||
|     FS::ArchiveInit(); |     FS::ArchiveInit(); | ||||||
|     ACT::Init(); |     ACT::Init(); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue