| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -2,8 +2,10 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Licensed under GPLv2 or any later version
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Refer to the license.txt file included.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <algorithm>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <array>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <cstring>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <list>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <mutex>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <unordered_map>
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#include <vector>
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -37,9 +39,12 @@ static ConnectionStatus connection_status{};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/* 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, so this always contains at least 1 entry.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * The first node is always the host.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static NodeList node_info(1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static NodeList node_info;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Node information about our own system.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static NodeInfo current_node;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Mapping of bind node ids to their respective events.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static std::unordered_map<u32, Kernel::SharedPtr<Kernel::Event>> bind_node_events;
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -54,6 +59,10 @@ static NetworkInfo network_info;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Event that will generate and send the 802.11 beacon frames.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static int beacon_broadcast_event;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Mutex to synchronize access to the connection status between the emulation thread and the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// network thread.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static std::mutex connection_status_mutex;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Mutex to synchronize access to the list of received beacons between the emulation thread and the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// network thread.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static std::mutex beacon_mutex;
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -63,14 +72,26 @@ static std::mutex beacon_mutex;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				constexpr size_t MaxBeaconFrames = 15;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// List of the last <MaxBeaconFrames> beacons received from the network.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static std::deque<Network::WifiPacket> received_beacons;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static std::list<Network::WifiPacket> received_beacons;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * Returns a list of received 802.11 beacon frames from the specified sender since the last call.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				std::deque<Network::WifiPacket> GetReceivedBeacons(const MacAddress& sender) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				std::list<Network::WifiPacket> GetReceivedBeacons(const MacAddress& sender) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    std::lock_guard<std::mutex> lock(beacon_mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(Subv): Filter by sender.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (sender != Network::BroadcastMac) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        std::list<Network::WifiPacket> filtered_list;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        const auto beacon = std::find_if(received_beacons.begin(), received_beacons.end(),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                         [&sender](const Network::WifiPacket& packet) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                             return packet.transmitter_address == sender;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                         });
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (beacon != received_beacons.end()) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            filtered_list.push_back(*beacon);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // TODO(B3N30): Check if the complete deque is cleared or just the fetched entries
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            received_beacons.erase(beacon);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return filtered_list;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return std::move(received_beacons);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -83,6 +104,15 @@ void SendPacket(Network::WifiPacket& packet) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// limit is exceeded.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void 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(),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                     [&packet](const Network::WifiPacket& new_packet) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                         return new_packet.transmitter_address == packet.transmitter_address;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                     });
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (unique_beacon != received_beacons.end()) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // We already have a beacon from the same mac in the deque, remove the old one;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        received_beacons.erase(unique_beacon);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    received_beacons.emplace_back(packet);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -91,14 +121,33 @@ void HandleBeaconFrame(const Network::WifiPacket& packet) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        received_beacons.pop_front();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void HandleAssociationResponseFrame(const Network::WifiPacket& packet) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    auto assoc_result = GetAssociationResult(packet.data);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ASSERT_MSG(std::get<AssocStatus>(assoc_result) == AssocStatus::Successful,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				               "Could not join network");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        std::lock_guard<std::mutex> lock(connection_status_mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ASSERT(connection_status.status == static_cast<u32>(NetworkStatus::Connecting));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Send the EAPoL-Start packet to the server.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    using Network::WifiPacket;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    WifiPacket eapol_start;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    eapol_start.channel = network_channel;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    eapol_start.data = GenerateEAPoLStartFrame(std::get<u16>(assoc_result), current_node);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(B3N30): Encrypt the packet.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    eapol_start.destination_address = packet.transmitter_address;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    eapol_start.type = WifiPacket::PacketType::Data;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    SendPacket(eapol_start);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/*
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * Returns an available index in the nodes array for the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * currently-hosted UDS network.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				static u16 GetNextAvailableNodeId() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				               "Can not accept clients if we're not hosting a network");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    for (u16 index = 0; index < connection_status.max_nodes; ++index) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if ((connection_status.node_bitmask & (1 << index)) == 0)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return index;
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -113,35 +162,46 @@ static u16 GetNextAvailableNodeId() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * authentication frame with SEQ1.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 */
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void StartConnectionSequence(const MacAddress& server) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ASSERT(connection_status.status == static_cast<u32>(NetworkStatus::NotConnected));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(Subv): Handle timeout.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Send an authentication frame with SEQ1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    using Network::WifiPacket;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    WifiPacket auth_request;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    auth_request.channel = network_channel;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    auth_request.destination_address = server;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    auth_request.type = WifiPacket::PacketType::Authentication;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        std::lock_guard<std::mutex> lock(connection_status_mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ASSERT(connection_status.status == static_cast<u32>(NetworkStatus::NotConnected));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // TODO(Subv): Handle timeout.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Send an authentication frame with SEQ1
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        auth_request.channel = network_channel;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ1);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        auth_request.destination_address = server;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        auth_request.type = WifiPacket::PacketType::Authentication;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    SendPacket(auth_request);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/// Sends an Association Response frame to the specified mac address
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void SendAssociationResponseFrame(const MacAddress& address) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    using Network::WifiPacket;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    WifiPacket assoc_response;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    assoc_response.channel = network_channel;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(Subv): This will cause multiple clients to end up with the same association id, but
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // we're not using that for anything.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u16 association_id = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    assoc_response.data = GenerateAssocResponseFrame(AssocStatus::Successful, association_id,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                                     network_info.network_id);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    assoc_response.destination_address = address;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    assoc_response.type = WifiPacket::PacketType::AssociationResponse;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        std::lock_guard<std::mutex> lock(connection_status_mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            LOG_ERROR(Service_NWM, "Connection sequence aborted, because connection status is %u",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                      connection_status.status);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assoc_response.channel = network_channel;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // TODO(Subv): This will cause multiple clients to end up with the same association id, but
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // we're not using that for anything.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        u16 association_id = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assoc_response.data = GenerateAssocResponseFrame(AssocStatus::Successful, association_id,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                                         network_info.network_id);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assoc_response.destination_address = address;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        assoc_response.type = WifiPacket::PacketType::AssociationResponse;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    SendPacket(assoc_response);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -155,16 +215,23 @@ void SendAssociationResponseFrame(const MacAddress& address) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				void 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) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ASSERT_MSG(connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Respond with an authentication response frame with SEQ2
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        using Network::WifiPacket;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        WifiPacket auth_request;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        auth_request.channel = network_channel;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ2);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        auth_request.destination_address = packet.transmitter_address;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        auth_request.type = WifiPacket::PacketType::Authentication;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            std::lock_guard<std::mutex> lock(connection_status_mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                LOG_ERROR(Service_NWM,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                          "Connection sequence aborted, because connection status is %u",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                          connection_status.status);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            // Respond with an authentication response frame with SEQ2
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            auth_request.channel = network_channel;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            auth_request.data = GenerateAuthenticationFrame(AuthenticationSeq::SEQ2);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            auth_request.destination_address = packet.transmitter_address;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            auth_request.type = WifiPacket::PacketType::Authentication;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        SendPacket(auth_request);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        SendAssociationResponseFrame(packet.transmitter_address);
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -180,6 +247,9 @@ void OnWifiPacketReceived(const Network::WifiPacket& packet) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case Network::WifiPacket::PacketType::Authentication:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        HandleAuthenticationFrame(packet);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    case Network::WifiPacket::PacketType::AssociationResponse:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        HandleAssociationResponseFrame(packet);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        break;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -305,7 +375,7 @@ static void InitializeWithVersion(Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u32 sharedmem_size = rp.Pop<u32>();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Update the node information with the data the game gave us.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    rp.PopRaw(node_info[0]);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    rp.PopRaw(current_node);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u16 version = rp.Pop<u16>();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -315,10 +385,14 @@ static void InitializeWithVersion(Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ASSERT_MSG(recv_buffer_memory->size == sharedmem_size, "Invalid shared memory size.");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Reset the connection status, it contains all zeros after initialization,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // except for the actual status value.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status = {};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status.status = static_cast<u32>(NetworkStatus::NotConnected);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        std::lock_guard<std::mutex> lock(connection_status_mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Reset the connection status, it contains all zeros after initialization,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // except for the actual status value.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status = {};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status.status = static_cast<u32>(NetworkStatus::NotConnected);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    rb.Push(RESULT_SUCCESS);
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -348,12 +422,16 @@ static void GetConnectionStatus(Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    IPC::RequestBuilder rb = rp.MakeBuilder(13, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    rb.Push(RESULT_SUCCESS);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    rb.PushRaw(connection_status);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        std::lock_guard<std::mutex> lock(connection_status_mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        rb.PushRaw(connection_status);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Reset the bitmask of changed nodes after each call to this
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // function to prevent falsely informing games of outstanding
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // changes in subsequent calls.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status.changed_nodes = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Reset the bitmask of changed nodes after each call to this
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // function to prevent falsely informing games of outstanding
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // changes in subsequent calls.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // TODO(Subv): Find exactly where the NWM module resets this value.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status.changed_nodes = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    LOG_DEBUG(Service_NWM, "called");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -434,31 +512,36 @@ static void BeginHostingNetwork(Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // 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.");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status.status = static_cast<u32>(NetworkStatus::ConnectedAsHost);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        std::lock_guard<std::mutex> lock(connection_status_mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status.status = static_cast<u32>(NetworkStatus::ConnectedAsHost);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Ensure the application data size is less than the maximum value.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    ASSERT_MSG(network_info.application_data_size <= ApplicationDataSize, "Data size is too big.");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Ensure the application data size is less than the maximum value.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ASSERT_MSG(network_info.application_data_size <= ApplicationDataSize,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                   "Data size is too big.");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Set up basic information for this network.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    network_info.oui_value = NintendoOUI;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    network_info.oui_type = static_cast<u8>(NintendoTagId::NetworkInfo);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Set up basic information for this network.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        network_info.oui_value = NintendoOUI;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        network_info.oui_type = static_cast<u8>(NintendoTagId::NetworkInfo);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status.max_nodes = network_info.max_nodes;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status.max_nodes = network_info.max_nodes;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Resize the nodes list to hold max_nodes.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    node_info.resize(network_info.max_nodes);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Resize the nodes list to hold max_nodes.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        node_info.resize(network_info.max_nodes);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // There's currently only one node in the network (the host).
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status.total_nodes = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    network_info.total_nodes = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // The host is always the first node
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status.network_node_id = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    node_info[0].network_node_id = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status.nodes[0] = connection_status.network_node_id;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Set the bit 0 in the nodes bitmask to indicate that node 1 is already taken.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status.node_bitmask |= 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Notify the application that the first node was set.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status.changed_nodes |= 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // There's currently only one node in the network (the host).
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status.total_nodes = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        network_info.total_nodes = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // The host is always the first node
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status.network_node_id = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        current_node.network_node_id = 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status.nodes[0] = connection_status.network_node_id;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Set the bit 0 in the nodes bitmask to indicate that node 1 is already taken.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status.node_bitmask |= 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // Notify the application that the first node was set.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status.changed_nodes |= 1;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        node_info[0] = current_node;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // If the game has a preferred channel, use that instead.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (network_info.channel != 0)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -495,9 +578,13 @@ static void DestroyNetwork(Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // Unschedule the beacon broadcast event.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(Subv): Check if connection_status is indeed reset after this call.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status = {};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status.status = static_cast<u8>(NetworkStatus::NotConnected);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        std::lock_guard<std::mutex> lock(connection_status_mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        // TODO(Subv): Check if connection_status is indeed reset after this call.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status = {};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status.status = static_cast<u8>(NetworkStatus::NotConnected);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status_event->Signal();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -540,17 +627,24 @@ static void SendTo(Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsClient) &&
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::UDS,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                           ErrorSummary::InvalidState, ErrorLevel::Status));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u16 network_node_id;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    if (dest_node_id == connection_status.network_node_id) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::UDS,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                           ErrorSummary::WrongArgument, ErrorLevel::Status));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        std::lock_guard<std::mutex> lock(connection_status_mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsClient) &&
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            connection_status.status != static_cast<u32>(NetworkStatus::ConnectedAsHost)) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::UDS,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                               ErrorSummary::InvalidState, ErrorLevel::Status));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if (dest_node_id == connection_status.network_node_id) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::UDS,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                               ErrorSummary::WrongArgument, ErrorLevel::Status));
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        network_node_id = connection_status.network_node_id;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(Subv): Do something with the flags.
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -567,8 +661,8 @@ static void SendTo(Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(Subv): Increment the sequence number after each sent packet.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u16 sequence_number = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    std::vector<u8> data_payload = GenerateDataPayload(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        data, data_channel, dest_node_id, connection_status.network_node_id, sequence_number);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    std::vector<u8> data_payload =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        GenerateDataPayload(data, data_channel, dest_node_id, network_node_id, sequence_number);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // TODO(Subv): Retrieve the MAC address of the dest_node_id and our own to encrypt
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    // and encapsulate the payload.
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -595,6 +689,7 @@ static void GetChannel(Interface* self) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1A, 0, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    std::lock_guard<std::mutex> lock(connection_status_mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    bool is_connected = connection_status.status != static_cast<u32>(NetworkStatus::NotConnected);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    u8 channel = is_connected ? network_channel : 0;
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -766,6 +861,7 @@ static void BeaconBroadcastCallback(u64 userdata, int cycles_late) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * @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,
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -827,8 +923,11 @@ NWM_UDS::~NWM_UDS() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status_event = nullptr;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    recv_buffer_memory = nullptr;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status = {};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    connection_status.status = static_cast<u32>(NetworkStatus::NotConnected);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        std::lock_guard<std::mutex> lock(connection_status_mutex);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status = {};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        connection_status.status = static_cast<u32>(NetworkStatus::NotConnected);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    }
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    CoreTiming::UnscheduleEvent(beacon_broadcast_event, 0);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				 
 |