mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	NWM_UDS: move states into the class
This commit is contained in:
		
							parent
							
								
									bad2e084e3
								
							
						
					
					
						commit
						6382d9bfc3
					
				
					 2 changed files with 148 additions and 125 deletions
				
			
		|  | @ -3,15 +3,7 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <array> | ||||
| #include <atomic> | ||||
| #include <cstring> | ||||
| #include <list> | ||||
| #include <map> | ||||
| #include <mutex> | ||||
| #include <unordered_map> | ||||
| #include <vector> | ||||
| #include <boost/optional.hpp> | ||||
| #include <cryptopp/osrng.h> | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
|  | @ -28,7 +20,6 @@ | |||
| #include "core/hle/service/nwm/uds_connection.h" | ||||
| #include "core/hle/service/nwm/uds_data.h" | ||||
| #include "core/memory.h" | ||||
| #include "network/network.h" | ||||
| 
 | ||||
| namespace Service::NWM { | ||||
| 
 | ||||
|  | @ -39,87 +30,17 @@ enum { | |||
| }; | ||||
| } // namespace ErrCodes
 | ||||
| 
 | ||||
| // Event that is signaled every time the connection status changes.
 | ||||
| static Kernel::SharedPtr<Kernel::Event> connection_status_event; | ||||
| 
 | ||||
| // Shared memory provided by the application to store the receive buffer.
 | ||||
| // This is not currently used.
 | ||||
| static Kernel::SharedPtr<Kernel::SharedMemory> recv_buffer_memory; | ||||
| 
 | ||||
| // Connection status of this 3DS.
 | ||||
| static ConnectionStatus connection_status{}; | ||||
| 
 | ||||
| static std::atomic<bool> initialized(false); | ||||
| 
 | ||||
| /* Node information about the current network.
 | ||||
|  * The amount of elements in this vector is always the maximum number | ||||
|  * of nodes specified in the network configuration. | ||||
|  * The first node is always the host. | ||||
|  */ | ||||
| static NodeList node_info; | ||||
| 
 | ||||
| // Node information about our own system.
 | ||||
| static NodeInfo current_node; | ||||
| 
 | ||||
| struct BindNodeData { | ||||
|     u32 bind_node_id;    ///< Id of the bind node associated with this data.
 | ||||
|     u8 channel;          ///< Channel that this bind node was bound to.
 | ||||
|     u16 network_node_id; ///< Node id this bind node is associated with, only packets from this
 | ||||
|                          /// network node will be received.
 | ||||
|     Kernel::SharedPtr<Kernel::Event> event;       ///< Receive event for this bind node.
 | ||||
|     std::deque<std::vector<u8>> received_packets; ///< List of packets received on this channel.
 | ||||
| }; | ||||
| 
 | ||||
| // Mapping of data channels to their internal data.
 | ||||
| static std::unordered_map<u32, BindNodeData> channel_data; | ||||
| 
 | ||||
| // The WiFi network channel that the network is currently on.
 | ||||
| // Since we're not actually interacting with physical radio waves, this is just a dummy value.
 | ||||
| static u8 network_channel = DefaultNetworkChannel; | ||||
| 
 | ||||
| // Information about the network that we're currently connected to.
 | ||||
| static NetworkInfo network_info; | ||||
| 
 | ||||
| // Mapping of mac addresses to their respective node_ids.
 | ||||
| struct Node { | ||||
|     bool connected; | ||||
|     u16 node_id; | ||||
| }; | ||||
| static std::map<MacAddress, Node> node_map; | ||||
| 
 | ||||
| // Event that will generate and send the 802.11 beacon frames.
 | ||||
| static Core::TimingEventType* 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
 | ||||
| // network thread.
 | ||||
| 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
 | ||||
| // network thread.
 | ||||
| static std::mutex beacon_mutex; | ||||
| 
 | ||||
| // Number of beacons to store before we start dropping the old ones.
 | ||||
| // TODO(Subv): Find a more accurate value for this limit.
 | ||||
| constexpr std::size_t MaxBeaconFrames = 15; | ||||
| 
 | ||||
| // List of the last <MaxBeaconFrames> beacons received from the network.
 | ||||
| static std::list<Network::WifiPacket> received_beacons; | ||||
| 
 | ||||
| // Network node id used when a SecureData packet is addressed to every connected node.
 | ||||
| constexpr u16 BroadcastNetworkNodeId = 0xFFFF; | ||||
| 
 | ||||
| // The Host has always dest_node_id 1
 | ||||
| constexpr u16 HostDestNodeId = 1; | ||||
| 
 | ||||
| /**
 | ||||
|  * Returns a list of received 802.11 beacon frames from the specified sender since the last call. | ||||
|  */ | ||||
| std::list<Network::WifiPacket> GetReceivedBeacons(const MacAddress& sender) { | ||||
| std::list<Network::WifiPacket> NWM_UDS::GetReceivedBeacons(const MacAddress& sender) { | ||||
|     std::lock_guard<std::mutex> lock(beacon_mutex); | ||||
|     if (sender != Network::BroadcastMac) { | ||||
|         std::list<Network::WifiPacket> filtered_list; | ||||
|  | @ -149,11 +70,7 @@ void SendPacket(Network::WifiPacket& packet) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Returns an available index in the nodes array for the | ||||
|  * currently-hosted UDS network. | ||||
|  */ | ||||
| static u16 GetNextAvailableNodeId() { | ||||
| u16 NWM_UDS::GetNextAvailableNodeId() { | ||||
|     for (u16 index = 0; index < connection_status.max_nodes; ++index) { | ||||
|         if ((connection_status.node_bitmask & (1 << index)) == 0) | ||||
|             return index + 1; | ||||
|  | @ -163,7 +80,7 @@ static u16 GetNextAvailableNodeId() { | |||
|     ASSERT_MSG(false, "No available connection slots in the network"); | ||||
| } | ||||
| 
 | ||||
| static void BroadcastNodeMap() { | ||||
| void NWM_UDS::BroadcastNodeMap() { | ||||
|     // Note: This is not how UDS on a 3ds does it but it shouldn't be
 | ||||
|     // necessary for citra
 | ||||
|     Network::WifiPacket packet; | ||||
|  | @ -189,7 +106,7 @@ static void BroadcastNodeMap() { | |||
|     SendPacket(packet); | ||||
| } | ||||
| 
 | ||||
| static void HandleNodeMapPacket(const Network::WifiPacket& packet) { | ||||
| void NWM_UDS::HandleNodeMapPacket(const Network::WifiPacket& packet) { | ||||
|     std::lock_guard<std::mutex> lock(connection_status_mutex); | ||||
|     if (connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost)) { | ||||
|         LOG_DEBUG(Service_NWM, "Ignored NodeMapPacket since connection_status is host"); | ||||
|  | @ -211,9 +128,7 @@ static void HandleNodeMapPacket(const Network::WifiPacket& packet) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| // Inserts the received beacon frame in the beacon queue and removes any older beacons if the size
 | ||||
| // limit is exceeded.
 | ||||
| void HandleBeaconFrame(const Network::WifiPacket& packet) { | ||||
| void NWM_UDS::HandleBeaconFrame(const Network::WifiPacket& packet) { | ||||
|     std::lock_guard<std::mutex> lock(beacon_mutex); | ||||
|     const auto unique_beacon = | ||||
|         std::find_if(received_beacons.begin(), received_beacons.end(), | ||||
|  | @ -232,7 +147,7 @@ void HandleBeaconFrame(const Network::WifiPacket& packet) { | |||
|         received_beacons.pop_front(); | ||||
| } | ||||
| 
 | ||||
| void HandleAssociationResponseFrame(const Network::WifiPacket& packet) { | ||||
| void NWM_UDS::HandleAssociationResponseFrame(const Network::WifiPacket& packet) { | ||||
|     auto assoc_result = GetAssociationResult(packet.data); | ||||
| 
 | ||||
|     ASSERT_MSG(std::get<AssocStatus>(assoc_result) == AssocStatus::Successful, | ||||
|  | @ -259,7 +174,7 @@ void HandleAssociationResponseFrame(const Network::WifiPacket& packet) { | |||
|     SendPacket(eapol_start); | ||||
| } | ||||
| 
 | ||||
| static void HandleEAPoLPacket(const Network::WifiPacket& packet) { | ||||
| void NWM_UDS::HandleEAPoLPacket(const Network::WifiPacket& packet) { | ||||
|     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); | ||||
|  | @ -378,7 +293,7 @@ static void HandleEAPoLPacket(const Network::WifiPacket& packet) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| static void HandleSecureDataPacket(const Network::WifiPacket& packet) { | ||||
| void NWM_UDS::HandleSecureDataPacket(const Network::WifiPacket& packet) { | ||||
|     auto secure_data = ParseSecureDataHeader(packet.data); | ||||
|     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); | ||||
|  | @ -439,11 +354,7 @@ static void HandleSecureDataPacket(const Network::WifiPacket& packet) { | |||
|     channel_info->second.event->Signal(); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Start a connection sequence with an UDS server. The sequence starts by sending an 802.11 | ||||
|  * authentication frame with SEQ1. | ||||
|  */ | ||||
| void StartConnectionSequence(const MacAddress& server) { | ||||
| void NWM_UDS::StartConnectionSequence(const MacAddress& server) { | ||||
|     using Network::WifiPacket; | ||||
|     WifiPacket auth_request; | ||||
|     { | ||||
|  | @ -462,8 +373,7 @@ void StartConnectionSequence(const MacAddress& server) { | |||
|     SendPacket(auth_request); | ||||
| } | ||||
| 
 | ||||
| /// Sends an Association Response frame to the specified mac address
 | ||||
| void SendAssociationResponseFrame(const MacAddress& address) { | ||||
| void NWM_UDS::SendAssociationResponseFrame(const MacAddress& address) { | ||||
|     using Network::WifiPacket; | ||||
|     WifiPacket assoc_response; | ||||
| 
 | ||||
|  | @ -488,13 +398,7 @@ void SendAssociationResponseFrame(const MacAddress& address) { | |||
|     SendPacket(assoc_response); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Handles the authentication request frame and sends the authentication response and association | ||||
|  * response frames. Once an Authentication frame with SEQ1 is received by the server, it responds | ||||
|  * with an Authentication frame containing SEQ2, and immediately sends an Association response frame | ||||
|  * containing the details of the access point and the assigned association id for the new client. | ||||
|  */ | ||||
| void HandleAuthenticationFrame(const Network::WifiPacket& packet) { | ||||
| void NWM_UDS::HandleAuthenticationFrame(const Network::WifiPacket& packet) { | ||||
|     // Only the SEQ1 auth frame is handled here, the SEQ2 frame doesn't need any special behavior
 | ||||
|     if (GetAuthenticationSeqNumber(packet.data) == AuthenticationSeq::SEQ1) { | ||||
|         using Network::WifiPacket; | ||||
|  | @ -532,8 +436,7 @@ 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) { | ||||
| void NWM_UDS::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); | ||||
|  | @ -573,7 +476,7 @@ void HandleDeauthenticationFrame(const Network::WifiPacket& packet) { | |||
|     connection_status_event->Signal(); | ||||
| } | ||||
| 
 | ||||
| static void HandleDataFrame(const Network::WifiPacket& packet) { | ||||
| void NWM_UDS::HandleDataFrame(const Network::WifiPacket& packet) { | ||||
|     switch (GetFrameEtherType(packet.data)) { | ||||
|     case EtherType::EAPoL: | ||||
|         HandleEAPoLPacket(packet); | ||||
|  | @ -585,7 +488,7 @@ static void HandleDataFrame(const Network::WifiPacket& packet) { | |||
| } | ||||
| 
 | ||||
| /// Callback to parse and handle a received wifi packet.
 | ||||
| void OnWifiPacketReceived(const Network::WifiPacket& packet) { | ||||
| void NWM_UDS::OnWifiPacketReceived(const Network::WifiPacket& packet) { | ||||
|     switch (packet.type) { | ||||
|     case Network::WifiPacket::PacketType::Beacon: | ||||
|         HandleBeaconFrame(packet); | ||||
|  | @ -608,7 +511,7 @@ void OnWifiPacketReceived(const Network::WifiPacket& packet) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| static boost::optional<Network::MacAddress> GetNodeMacAddress(u16 dest_node_id, u8 flags) { | ||||
| boost::optional<Network::MacAddress> NWM_UDS::GetNodeMacAddress(u16 dest_node_id, u8 flags) { | ||||
|     constexpr u8 BroadcastFlag = 0x2; | ||||
|     if ((flags & BroadcastFlag) || dest_node_id == BroadcastNetworkNodeId) { | ||||
|         // Broadcast
 | ||||
|  | @ -729,7 +632,8 @@ void NWM_UDS::InitializeWithVersion(Kernel::HLERequestContext& ctx) { | |||
|     ASSERT_MSG(recv_buffer_memory->GetSize() == sharedmem_size, "Invalid shared memory size."); | ||||
| 
 | ||||
|     if (auto room_member = Network::GetRoomMember().lock()) { | ||||
|         wifi_packet_received = room_member->BindOnWifiPacketReceived(OnWifiPacketReceived); | ||||
|         wifi_packet_received = room_member->BindOnWifiPacketReceived( | ||||
|             [this](const Network::WifiPacket& packet) { OnWifiPacketReceived(packet); }); | ||||
|     } else { | ||||
|         LOG_ERROR(Service_NWM, "Network isn't initalized"); | ||||
|     } | ||||
|  | @ -1417,18 +1321,6 @@ NWM_UDS::NWM_UDS(Core::System& system) : ServiceFramework("nwm::UDS"), system(sy | |||
| } | ||||
| 
 | ||||
| NWM_UDS::~NWM_UDS() { | ||||
|     network_info = {}; | ||||
|     channel_data.clear(); | ||||
|     connection_status_event = nullptr; | ||||
|     recv_buffer_memory = nullptr; | ||||
|     initialized = false; | ||||
| 
 | ||||
|     { | ||||
|         std::lock_guard<std::mutex> lock(connection_status_mutex); | ||||
|         connection_status = {}; | ||||
|         connection_status.status = static_cast<u32>(NetworkStatus::NotConnected); | ||||
|     } | ||||
| 
 | ||||
|     if (auto room_member = Network::GetRoomMember().lock()) | ||||
|         room_member->Unbind(wifi_packet_received); | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,20 +5,36 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| #include <atomic> | ||||
| #include <cstddef> | ||||
| #include <deque> | ||||
| #include <list> | ||||
| #include <map> | ||||
| #include <mutex> | ||||
| #include <unordered_map> | ||||
| #include <vector> | ||||
| #include <boost/optional.hpp> | ||||
| #include "common/common_types.h" | ||||
| #include "common/swap.h" | ||||
| #include "core/hle/kernel/kernel.h" | ||||
| #include "core/hle/service/service.h" | ||||
| #include "network/network.h" | ||||
| 
 | ||||
| namespace Core { | ||||
| class System; | ||||
| } | ||||
| 
 | ||||
| namespace Kernel { | ||||
| class Event; | ||||
| class SharedMemory; | ||||
| } // namespace Kernel
 | ||||
| 
 | ||||
| // Local-WLAN service
 | ||||
| 
 | ||||
| namespace Service::NWM { | ||||
| 
 | ||||
| using MacAddress = std::array<u8, 6>; | ||||
| 
 | ||||
| const std::size_t ApplicationDataSize = 0xC8; | ||||
| const u8 DefaultNetworkChannel = 11; | ||||
| 
 | ||||
|  | @ -354,6 +370,121 @@ private: | |||
|     void DecryptBeaconData(Kernel::HLERequestContext& ctx); | ||||
| 
 | ||||
|     void BeaconBroadcastCallback(u64 userdata, s64 cycles_late); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Returns a list of received 802.11 beacon frames from the specified sender since the last | ||||
|      * call. | ||||
|      */ | ||||
|     std::list<Network::WifiPacket> GetReceivedBeacons(const MacAddress& sender); | ||||
| 
 | ||||
|     /*
 | ||||
|      * Returns an available index in the nodes array for the | ||||
|      * currently-hosted UDS network. | ||||
|      */ | ||||
|     u16 GetNextAvailableNodeId(); | ||||
| 
 | ||||
|     void BroadcastNodeMap(); | ||||
|     void HandleNodeMapPacket(const Network::WifiPacket& packet); | ||||
|     void HandleBeaconFrame(const Network::WifiPacket& packet); | ||||
|     void HandleAssociationResponseFrame(const Network::WifiPacket& packet); | ||||
|     void HandleEAPoLPacket(const Network::WifiPacket& packet); | ||||
|     void HandleSecureDataPacket(const Network::WifiPacket& packet); | ||||
| 
 | ||||
|     /*
 | ||||
|      * Start a connection sequence with an UDS server. The sequence starts by sending an 802.11 | ||||
|      * authentication frame with SEQ1. | ||||
|      */ | ||||
|     void StartConnectionSequence(const MacAddress& server); | ||||
| 
 | ||||
|     /// Sends an Association Response frame to the specified mac address
 | ||||
|     void SendAssociationResponseFrame(const MacAddress& address); | ||||
| 
 | ||||
|     /*
 | ||||
|      * Handles the authentication request frame and sends the authentication response and | ||||
|      * association response frames. Once an Authentication frame with SEQ1 is received by the | ||||
|      * server, it responds with an Authentication frame containing SEQ2, and immediately sends an | ||||
|      * Association response frame containing the details of the access point and the assigned | ||||
|      * association id for the new client. | ||||
|      */ | ||||
|     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); | ||||
| 
 | ||||
|     void HandleDataFrame(const Network::WifiPacket& packet); | ||||
| 
 | ||||
|     /// Callback to parse and handle a received wifi packet.
 | ||||
|     void OnWifiPacketReceived(const Network::WifiPacket& packet); | ||||
| 
 | ||||
|     boost::optional<Network::MacAddress> GetNodeMacAddress(u16 dest_node_id, u8 flags); | ||||
| 
 | ||||
|     // Event that is signaled every time the connection status changes.
 | ||||
|     Kernel::SharedPtr<Kernel::Event> connection_status_event; | ||||
| 
 | ||||
|     // Shared memory provided by the application to store the receive buffer.
 | ||||
|     // This is not currently used.
 | ||||
|     Kernel::SharedPtr<Kernel::SharedMemory> recv_buffer_memory; | ||||
| 
 | ||||
|     // Connection status of this 3DS.
 | ||||
|     ConnectionStatus connection_status{}; | ||||
| 
 | ||||
|     std::atomic<bool> initialized{false}; | ||||
| 
 | ||||
|     /* Node information about the current network.
 | ||||
|      * The amount of elements in this vector is always the maximum number | ||||
|      * of nodes specified in the network configuration. | ||||
|      * The first node is always the host. | ||||
|      */ | ||||
|     NodeList node_info; | ||||
| 
 | ||||
|     // Node information about our own system.
 | ||||
|     NodeInfo current_node; | ||||
| 
 | ||||
|     struct BindNodeData { | ||||
|         u32 bind_node_id;    ///< Id of the bind node associated with this data.
 | ||||
|         u8 channel;          ///< Channel that this bind node was bound to.
 | ||||
|         u16 network_node_id; ///< Node id this bind node is associated with, only packets from this
 | ||||
|                              /// network node will be received.
 | ||||
|         Kernel::SharedPtr<Kernel::Event> event;       ///< Receive event for this bind node.
 | ||||
|         std::deque<std::vector<u8>> received_packets; ///< List of packets received on this channel.
 | ||||
|     }; | ||||
| 
 | ||||
|     // Mapping of data channels to their internal data.
 | ||||
|     std::unordered_map<u32, BindNodeData> channel_data; | ||||
| 
 | ||||
|     // The WiFi network channel that the network is currently on.
 | ||||
|     // Since we're not actually interacting with physical radio waves, this is just a dummy value.
 | ||||
|     u8 network_channel = DefaultNetworkChannel; | ||||
| 
 | ||||
|     // Information about the network that we're currently connected to.
 | ||||
|     NetworkInfo network_info; | ||||
| 
 | ||||
|     // Mapping of mac addresses to their respective node_ids.
 | ||||
|     struct Node { | ||||
|         bool connected; | ||||
|         u16 node_id; | ||||
|     }; | ||||
| 
 | ||||
|     std::map<MacAddress, Node> node_map; | ||||
| 
 | ||||
|     // Event that will generate and send the 802.11 beacon frames.
 | ||||
|     Core::TimingEventType* beacon_broadcast_event; | ||||
| 
 | ||||
|     // Callback identifier for the OnWifiPacketReceived event.
 | ||||
|     Network::RoomMember::CallbackHandle<Network::WifiPacket> wifi_packet_received; | ||||
| 
 | ||||
|     // Mutex to synchronize access to the connection status between the emulation thread and the
 | ||||
|     // network thread.
 | ||||
|     std::mutex connection_status_mutex; | ||||
| 
 | ||||
|     Kernel::SharedPtr<Kernel::Event> connection_event; | ||||
| 
 | ||||
|     // Mutex to synchronize access to the list of received beacons between the emulation thread and
 | ||||
|     // the network thread.
 | ||||
|     std::mutex beacon_mutex; | ||||
| 
 | ||||
|     // List of the last <MaxBeaconFrames> beacons received from the network.
 | ||||
|     std::list<Network::WifiPacket> received_beacons; | ||||
| }; | ||||
| 
 | ||||
| } // namespace Service::NWM
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue