diff --git a/src/core/hle/service/nwm/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp index 32b7ca2b8..b9b2b6989 100644 --- a/src/core/hle/service/nwm/nwm_uds.cpp +++ b/src/core/hle/service/nwm/nwm_uds.cpp @@ -279,6 +279,7 @@ void NWM_UDS::HandleEAPoLPacket(const Network::WifiPacket& packet) { // We're now connected, signal the application connection_status.status = static_cast(NetworkStatus::ConnectedAsClient); + connection_status.disconnect_reason = static_cast(DisconnectStatus::Connected); // Some games require ConnectToNetwork to block, for now it doesn't // If blocking is implemented this lock needs to be changed, // otherwise it might cause deadlocks @@ -648,6 +649,7 @@ ResultVal> NWM_UDS::Initialize( // Reset the connection status, it contains all zeros after initialization, // except for the actual status value. connection_status = {}; + connection_status.disconnect_reason = static_cast(DisconnectStatus::NotConnected); connection_status.status = static_cast(NetworkStatus::NotConnected); node_info.clear(); node_info.push_back(current_node); @@ -837,6 +839,7 @@ ResultCode NWM_UDS::BeginHostingNetwork(const u8* network_info_buffer, ASSERT_MSG(network_info.max_nodes > 1, "Trying to host a network of only one member."); connection_status.status = static_cast(NetworkStatus::ConnectedAsHost); + connection_status.disconnect_reason = static_cast(DisconnectStatus::Connected); // Ensure the application data size is less than the maximum value. ASSERT_MSG(network_info.application_data_size <= ApplicationDataSize, @@ -928,6 +931,57 @@ void NWM_UDS::BeginHostingNetworkDeprecated(Kernel::HLERequestContext& ctx) { rb.Push(result); } +void NWM_UDS::EjectClient(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x05, 1, 0); + const u16 network_node_id = rp.Pop(); + + LOG_WARNING(Service_NWM, "(stubbed) called"); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + + // The host can not be kicked. + if (network_node_id == 1) { + rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::UDS, + ErrorSummary::WrongArgument, ErrorLevel::Usage)); + return; + } + + std::lock_guard lock(connection_status_mutex); + if (connection_status.status != static_cast(NetworkStatus::ConnectedAsHost)) { + // Only the host can kick people. + rb.Push(ResultCode(ErrorDescription::NotAuthorized, ErrorModule::UDS, + ErrorSummary::InvalidState, ErrorLevel::Usage)); + LOG_WARNING(Service_NWM, "called with status {}", connection_status.status); + return; + } + + // This function always returns success if the status is valid. + rb.Push(RESULT_SUCCESS); + + using Network::WifiPacket; + Network::MacAddress dest_address = Network::BroadcastMac; + + if (network_node_id != BroadcastNetworkNodeId) { + auto address = GetNodeMacAddress(network_node_id, 0); + + if (!address) { + // There is no error if the network node id was not found. + return; + } + dest_address = *address; + } + + WifiPacket deauth; + deauth.channel = network_channel; + deauth.destination_address = dest_address; + deauth.type = WifiPacket::PacketType::Deauthentication; + SendPacket(deauth); + if (network_node_id == BroadcastNetworkNodeId) { + SendPacket(deauth); + SendPacket(deauth); + } +} + void NWM_UDS::UpdateNetworkAttribute(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x07, 2, 0); rp.Skip(2, false); @@ -1394,7 +1448,7 @@ NWM_UDS::NWM_UDS(Core::System& system) : ServiceFramework("nwm::UDS"), system(sy {0x00020000, nullptr, "Scrap"}, {0x00030000, &NWM_UDS::Shutdown, "Shutdown"}, {0x00040402, &NWM_UDS::BeginHostingNetworkDeprecated, "BeginHostingNetwork (deprecated)"}, - {0x00050040, nullptr, "EjectClient"}, + {0x00050040, &NWM_UDS::EjectClient, "EjectClient"}, {0x00060000, nullptr, "EjectSpectator"}, {0x00070080, &NWM_UDS::UpdateNetworkAttribute, "UpdateNetworkAttribute"}, {0x00080000, &NWM_UDS::DestroyNetwork, "DestroyNetwork"}, diff --git a/src/core/hle/service/nwm/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h index eeacf9676..c5bff31ac 100644 --- a/src/core/hle/service/nwm/nwm_uds.h +++ b/src/core/hle/service/nwm/nwm_uds.h @@ -73,9 +73,15 @@ enum class NetworkStatus { ConnectedAsSpectator = 10, }; +enum class DisconnectStatus { + Connected = 1, + NotConnected = 2, + // TODO(B3N30): Figure out the other values +}; + struct ConnectionStatus { u32_le status; - INSERT_PADDING_WORDS(1); + u32_le disconnect_reason; u16_le network_node_id; u16_le changed_nodes; u16_le nodes[UDSMaxNodes]; @@ -409,6 +415,17 @@ private: */ void ConnectToNetworkDeprecated(Kernel::HLERequestContext& ctx); + /** + * NWM_UDS::EjectClient Disconnects clients. + * Inputs: + * 0 : Command header + * 1 : Network node id + * Outputs: + * 0 : Return header + * 1 : Result of function, 0 on success, otherwise error code + */ + void EjectClient(Kernel::HLERequestContext& ctx); + /** * NWM_UDS::DecryptBeaconData service function. * Decrypts the encrypted data tags contained in the 802.11 beacons.