NWM_UDS:: Check flags in SendTo (#3481)
* NWM_UDS:: Check flags in SendTo * NWM_UDS: SendTo from Host to only oneClient * fix u8 in flags * Send node_map to clients * Libnetwork: Increase libnetwork version * Broadcast on dest_node_id 0xFFFF * fixup: dest_node_id offset * fixup: dest_node_id offset part 2 * Adressed wwyleles feedback * Adressed wwylele's nits
This commit is contained in:
parent
05cf7fe70a
commit
4be12d5f56
3 changed files with 92 additions and 21 deletions
|
@ -144,13 +144,50 @@ void SendPacket(Network::WifiPacket& packet) {
|
||||||
static u16 GetNextAvailableNodeId() {
|
static u16 GetNextAvailableNodeId() {
|
||||||
for (u16 index = 0; index < connection_status.max_nodes; ++index) {
|
for (u16 index = 0; index < connection_status.max_nodes; ++index) {
|
||||||
if ((connection_status.node_bitmask & (1 << index)) == 0)
|
if ((connection_status.node_bitmask & (1 << index)) == 0)
|
||||||
return index;
|
return index + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any connection attempts to an already full network should have been refused.
|
// Any connection attempts to an already full network should have been refused.
|
||||||
ASSERT_MSG(false, "No available connection slots in the network");
|
ASSERT_MSG(false, "No available connection slots in the network");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void BroadcastNodeMap() {
|
||||||
|
// Note: This is not how UDS on a 3ds does it but it shouldn't be
|
||||||
|
// necessary for citra
|
||||||
|
Network::WifiPacket packet;
|
||||||
|
packet.channel = network_channel;
|
||||||
|
packet.type = Network::WifiPacket::PacketType::NodeMap;
|
||||||
|
packet.destination_address = Network::BroadcastMac;
|
||||||
|
size_t size = node_map.size();
|
||||||
|
packet.data.resize(sizeof(size) + (sizeof(Network::MacAddress) + sizeof(u32)) * size);
|
||||||
|
std::memcpy(packet.data.data(), &size, sizeof(size));
|
||||||
|
size_t offset = sizeof(size);
|
||||||
|
for (const auto& node : node_map) {
|
||||||
|
std::memcpy(packet.data.data() + offset, node.first.data(), sizeof(node.first));
|
||||||
|
std::memcpy(packet.data.data() + offset + sizeof(node.first), &node.second,
|
||||||
|
sizeof(node.second));
|
||||||
|
offset += sizeof(Network::MacAddress) + sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
SendPacket(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HandleNodeMapPacket(const Network::WifiPacket& packet) {
|
||||||
|
std::lock_guard<std::mutex> lock(connection_status_mutex);
|
||||||
|
node_map.clear();
|
||||||
|
size_t num_entries;
|
||||||
|
Network::MacAddress address;
|
||||||
|
u32 id;
|
||||||
|
std::memcpy(&num_entries, packet.data.data(), sizeof(num_entries));
|
||||||
|
size_t offset = sizeof(num_entries);
|
||||||
|
for (size_t i = 0; i < num_entries; ++i) {
|
||||||
|
std::memcpy(&address, packet.data.data() + offset, sizeof(address));
|
||||||
|
std::memcpy(&id, packet.data.data() + offset + sizeof(address), sizeof(id));
|
||||||
|
node_map[address] = id;
|
||||||
|
offset += sizeof(address) + sizeof(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Inserts the received beacon frame in the beacon queue and removes any older beacons if the size
|
// Inserts the received beacon frame in the beacon queue and removes any older beacons if the size
|
||||||
// limit is exceeded.
|
// limit is exceeded.
|
||||||
void HandleBeaconFrame(const Network::WifiPacket& packet) {
|
void HandleBeaconFrame(const Network::WifiPacket& packet) {
|
||||||
|
@ -217,11 +254,11 @@ static void HandleEAPoLPacket(const Network::WifiPacket& packet) {
|
||||||
|
|
||||||
// Get an unused network node id
|
// Get an unused network node id
|
||||||
u16 node_id = GetNextAvailableNodeId();
|
u16 node_id = GetNextAvailableNodeId();
|
||||||
node.network_node_id = node_id + 1;
|
node.network_node_id = node_id;
|
||||||
|
|
||||||
connection_status.node_bitmask |= 1 << node_id;
|
connection_status.node_bitmask |= 1 << (node_id - 1);
|
||||||
connection_status.changed_nodes |= 1 << node_id;
|
connection_status.changed_nodes |= 1 << (node_id - 1);
|
||||||
connection_status.nodes[node_id] = node.network_node_id;
|
connection_status.nodes[node_id - 1] = node.network_node_id;
|
||||||
connection_status.total_nodes++;
|
connection_status.total_nodes++;
|
||||||
|
|
||||||
u8 current_nodes = network_info.total_nodes;
|
u8 current_nodes = network_info.total_nodes;
|
||||||
|
@ -229,7 +266,9 @@ static void HandleEAPoLPacket(const Network::WifiPacket& packet) {
|
||||||
|
|
||||||
network_info.total_nodes++;
|
network_info.total_nodes++;
|
||||||
|
|
||||||
node_map[packet.transmitter_address] = node_id;
|
node_map[packet.transmitter_address] = node.network_node_id;
|
||||||
|
|
||||||
|
BroadcastNodeMap();
|
||||||
|
|
||||||
// Send the EAPoL-Logoff packet.
|
// Send the EAPoL-Logoff packet.
|
||||||
using Network::WifiPacket;
|
using Network::WifiPacket;
|
||||||
|
@ -243,8 +282,7 @@ static void HandleEAPoLPacket(const Network::WifiPacket& packet) {
|
||||||
eapol_logoff.type = WifiPacket::PacketType::Data;
|
eapol_logoff.type = WifiPacket::PacketType::Data;
|
||||||
|
|
||||||
SendPacket(eapol_logoff);
|
SendPacket(eapol_logoff);
|
||||||
// TODO(B3N30): Broadcast updated node list
|
|
||||||
// The 3ds does this presumably to support spectators.
|
|
||||||
connection_status_event->Signal();
|
connection_status_event->Signal();
|
||||||
} else {
|
} else {
|
||||||
if (connection_status.status != static_cast<u32>(NetworkStatus::Connecting)) {
|
if (connection_status.status != static_cast<u32>(NetworkStatus::Connecting)) {
|
||||||
|
@ -433,12 +471,12 @@ void HandleDeauthenticationFrame(const Network::WifiPacket& packet) {
|
||||||
|
|
||||||
u16 node_id = node_map[packet.transmitter_address];
|
u16 node_id = node_map[packet.transmitter_address];
|
||||||
auto node = std::find_if(node_info.begin(), node_info.end(), [&node_id](const NodeInfo& info) {
|
auto node = std::find_if(node_info.begin(), node_info.end(), [&node_id](const NodeInfo& info) {
|
||||||
return info.network_node_id == node_id + 1;
|
return info.network_node_id == node_id;
|
||||||
});
|
});
|
||||||
ASSERT(node != node_info.end());
|
ASSERT(node != node_info.end());
|
||||||
|
|
||||||
connection_status.node_bitmask &= ~(1 << node_id);
|
connection_status.node_bitmask &= ~(1 << (node_id - 1));
|
||||||
connection_status.changed_nodes |= 1 << node_id;
|
connection_status.changed_nodes |= 1 << (node_id - 1);
|
||||||
connection_status.total_nodes--;
|
connection_status.total_nodes--;
|
||||||
|
|
||||||
network_info.total_nodes--;
|
network_info.total_nodes--;
|
||||||
|
@ -474,6 +512,9 @@ void OnWifiPacketReceived(const Network::WifiPacket& packet) {
|
||||||
case Network::WifiPacket::PacketType::Deauthentication:
|
case Network::WifiPacket::PacketType::Deauthentication:
|
||||||
HandleDeauthenticationFrame(packet);
|
HandleDeauthenticationFrame(packet);
|
||||||
break;
|
break;
|
||||||
|
case Network::WifiPacket::PacketType::NodeMap:
|
||||||
|
HandleNodeMapPacket(packet);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,6 +528,7 @@ void NWM_UDS::Shutdown(Kernel::HLERequestContext& ctx) {
|
||||||
bind_node.second.event->Signal();
|
bind_node.second.event->Signal();
|
||||||
}
|
}
|
||||||
channel_data.clear();
|
channel_data.clear();
|
||||||
|
node_map.clear();
|
||||||
|
|
||||||
recv_buffer_memory.reset();
|
recv_buffer_memory.reset();
|
||||||
|
|
||||||
|
@ -813,6 +855,7 @@ void NWM_UDS::BeginHostingNetwork(Kernel::HLERequestContext& ctx) {
|
||||||
void NWM_UDS::UpdateNetworkAttribute(Kernel::HLERequestContext& ctx) {
|
void NWM_UDS::UpdateNetworkAttribute(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx, 0x07, 2, 0);
|
IPC::RequestParser rp(ctx, 0x07, 2, 0);
|
||||||
rp.Skip(2, false);
|
rp.Skip(2, false);
|
||||||
|
LOG_WARNING(Service_NWM, "stubbed");
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
@ -839,6 +882,7 @@ void NWM_UDS::DestroyNetwork(Kernel::HLERequestContext& ctx) {
|
||||||
connection_status = {};
|
connection_status = {};
|
||||||
connection_status.status = static_cast<u32>(NetworkStatus::NotConnected);
|
connection_status.status = static_cast<u32>(NetworkStatus::NotConnected);
|
||||||
connection_status.network_node_id = tmp_node_id;
|
connection_status.network_node_id = tmp_node_id;
|
||||||
|
node_map.clear();
|
||||||
connection_status_event->Signal();
|
connection_status_event->Signal();
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
@ -867,6 +911,7 @@ void NWM_UDS::DisconnectNetwork(Kernel::HLERequestContext& ctx) {
|
||||||
connection_status = {};
|
connection_status = {};
|
||||||
connection_status.status = static_cast<u32>(NetworkStatus::ConnectedAsHost);
|
connection_status.status = static_cast<u32>(NetworkStatus::ConnectedAsHost);
|
||||||
connection_status.network_node_id = tmp_node_id;
|
connection_status.network_node_id = tmp_node_id;
|
||||||
|
node_map.clear();
|
||||||
LOG_DEBUG(Service_NWM, "called as a host");
|
LOG_DEBUG(Service_NWM, "called as a host");
|
||||||
rb.Push(ResultCode(ErrCodes::WrongStatus, ErrorModule::UDS, ErrorSummary::InvalidState,
|
rb.Push(ResultCode(ErrCodes::WrongStatus, ErrorModule::UDS, ErrorSummary::InvalidState,
|
||||||
ErrorLevel::Status));
|
ErrorLevel::Status));
|
||||||
|
@ -876,6 +921,7 @@ void NWM_UDS::DisconnectNetwork(Kernel::HLERequestContext& ctx) {
|
||||||
connection_status = {};
|
connection_status = {};
|
||||||
connection_status.status = static_cast<u32>(NetworkStatus::NotConnected);
|
connection_status.status = static_cast<u32>(NetworkStatus::NotConnected);
|
||||||
connection_status.network_node_id = tmp_node_id;
|
connection_status.network_node_id = tmp_node_id;
|
||||||
|
node_map.clear();
|
||||||
connection_status_event->Signal();
|
connection_status_event->Signal();
|
||||||
|
|
||||||
deauth.channel = network_channel;
|
deauth.channel = network_channel;
|
||||||
|
@ -904,7 +950,10 @@ void NWM_UDS::SendTo(Kernel::HLERequestContext& ctx) {
|
||||||
u8 data_channel = rp.Pop<u8>();
|
u8 data_channel = rp.Pop<u8>();
|
||||||
rp.Skip(1, false);
|
rp.Skip(1, false);
|
||||||
u32 data_size = rp.Pop<u32>();
|
u32 data_size = rp.Pop<u32>();
|
||||||
u32 flags = rp.Pop<u32>();
|
u8 flags = rp.Pop<u8>();
|
||||||
|
|
||||||
|
// There should never be a dest_node_id of 0
|
||||||
|
ASSERT(dest_node_id != 0);
|
||||||
|
|
||||||
std::vector<u8> input_buffer = rp.PopStaticBuffer();
|
std::vector<u8> input_buffer = rp.PopStaticBuffer();
|
||||||
ASSERT(input_buffer.size() >= data_size);
|
ASSERT(input_buffer.size() >= data_size);
|
||||||
|
@ -921,12 +970,37 @@ void NWM_UDS::SendTo(Kernel::HLERequestContext& ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dest_node_id == connection_status.network_node_id) {
|
if (dest_node_id == connection_status.network_node_id) {
|
||||||
|
LOG_ERROR(Service_NWM, "tried to send packet to itself");
|
||||||
rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::UDS,
|
rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::UDS,
|
||||||
ErrorSummary::WrongArgument, ErrorLevel::Status));
|
ErrorSummary::WrongArgument, ErrorLevel::Status));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(B3N30): Do something with the flags.
|
Network::MacAddress dest_address;
|
||||||
|
|
||||||
|
if (flags >> 2) {
|
||||||
|
LOG_ERROR(Service_NWM, "Unexpected flags 0x%02X", flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & (0x1 << 1)) || dest_node_id == 0xFFFF) {
|
||||||
|
// Broadcast
|
||||||
|
dest_address = Network::BroadcastMac;
|
||||||
|
} else if (dest_node_id != 1) {
|
||||||
|
// Send to specific client
|
||||||
|
auto destination =
|
||||||
|
std::find_if(node_map.begin(), node_map.end(),
|
||||||
|
[dest_node_id](const auto& node) { return node.second == dest_node_id; });
|
||||||
|
if (destination == node_map.end()) {
|
||||||
|
LOG_ERROR(Service_NWM, "tried to send packet to unknown dest id %u", dest_node_id);
|
||||||
|
rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::UDS,
|
||||||
|
ErrorSummary::WrongArgument, ErrorLevel::Status));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dest_address = destination->first;
|
||||||
|
} else {
|
||||||
|
// Send message to host
|
||||||
|
dest_address = network_info.host_mac_address;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr size_t MaxSize = 0x5C6;
|
constexpr size_t MaxSize = 0x5C6;
|
||||||
if (data_size > MaxSize) {
|
if (data_size > MaxSize) {
|
||||||
|
@ -945,12 +1019,8 @@ void NWM_UDS::SendTo(Kernel::HLERequestContext& ctx) {
|
||||||
// and encapsulate the payload.
|
// and encapsulate the payload.
|
||||||
|
|
||||||
Network::WifiPacket packet;
|
Network::WifiPacket packet;
|
||||||
// Data frames are sent to the host, who then decides where to route it to. If we're the host,
|
|
||||||
// just directly broadcast the frame.
|
packet.destination_address = dest_address;
|
||||||
if (connection_status.status == static_cast<u32>(NetworkStatus::ConnectedAsHost))
|
|
||||||
packet.destination_address = Network::BroadcastMac;
|
|
||||||
else
|
|
||||||
packet.destination_address = network_info.host_mac_address;
|
|
||||||
packet.channel = network_channel;
|
packet.channel = network_channel;
|
||||||
packet.data = std::move(data_payload);
|
packet.data = std::move(data_payload);
|
||||||
packet.type = Network::WifiPacket::PacketType::Data;
|
packet.type = Network::WifiPacket::PacketType::Data;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
namespace Network {
|
namespace Network {
|
||||||
|
|
||||||
constexpr u32 network_version = 1; ///< The version of this Room and RoomMember
|
constexpr u32 network_version = 2; ///< The version of this Room and RoomMember
|
||||||
|
|
||||||
constexpr u16 DefaultRoomPort = 24872;
|
constexpr u16 DefaultRoomPort = 24872;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,8 @@ struct WifiPacket {
|
||||||
Data,
|
Data,
|
||||||
Authentication,
|
Authentication,
|
||||||
AssociationResponse,
|
AssociationResponse,
|
||||||
Deauthentication
|
Deauthentication,
|
||||||
|
NodeMap
|
||||||
};
|
};
|
||||||
PacketType type; ///< The type of 802.11 frame.
|
PacketType type; ///< The type of 802.11 frame.
|
||||||
std::vector<u8> data; ///< Raw 802.11 frame data, starting at the management frame header
|
std::vector<u8> data; ///< Raw 802.11 frame data, starting at the management frame header
|
||||||
|
|
Loading…
Reference in a new issue