aboutsummaryrefslogtreecommitdiff
path: root/src/core/hle/service
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service')
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp77
-rw-r--r--src/core/hle/service/ldn/errors.h12
-rw-r--r--src/core/hle/service/ldn/ldn.cpp436
-rw-r--r--src/core/hle/service/ldn/ldn.h6
-rw-r--r--src/core/hle/service/ldn/ldn_results.h27
-rw-r--r--src/core/hle/service/ldn/ldn_types.h284
-rw-r--r--src/core/hle/service/nifm/nifm.cpp342
-rw-r--r--src/core/hle/service/nifm/nifm.h27
-rw-r--r--src/core/hle/service/pcv/pcv.cpp93
-rw-r--r--src/core/hle/service/pcv/pcv.h91
-rw-r--r--src/core/hle/service/service.cpp7
-rw-r--r--src/core/hle/service/sockets/bsd.cpp40
-rw-r--r--src/core/hle/service/sockets/bsd.h13
-rw-r--r--src/core/hle/service/sockets/sockets.h6
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp2
15 files changed, 1218 insertions, 245 deletions
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 3c28dee76..cb29004e8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -163,28 +163,51 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
}
LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
const auto controller_type = controller.device->GetNpadStyleIndex();
+ const auto& body_colors = controller.device->GetColors();
+ const auto& battery_level = controller.device->GetBattery();
auto* shared_memory = controller.shared_memory;
if (controller_type == Core::HID::NpadStyleIndex::None) {
controller.styleset_changed_event->GetWritableEvent().Signal();
return;
}
+
+ // Reset memory values
shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None;
shared_memory->device_type.raw = 0;
shared_memory->system_properties.raw = 0;
+ shared_memory->joycon_color.attribute = ColorAttribute::NoController;
+ shared_memory->joycon_color.attribute = ColorAttribute::NoController;
+ shared_memory->fullkey_color = {};
+ shared_memory->joycon_color.left = {};
+ shared_memory->joycon_color.right = {};
+ shared_memory->battery_level_dual = {};
+ shared_memory->battery_level_left = {};
+ shared_memory->battery_level_right = {};
+
switch (controller_type) {
case Core::HID::NpadStyleIndex::None:
ASSERT(false);
break;
case Core::HID::NpadStyleIndex::ProController:
+ shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
+ shared_memory->fullkey_color.fullkey = body_colors.fullkey;
+ shared_memory->battery_level_dual = battery_level.dual.battery_level;
shared_memory->style_tag.fullkey.Assign(1);
shared_memory->device_type.fullkey.Assign(1);
shared_memory->system_properties.is_vertical.Assign(1);
shared_memory->system_properties.use_plus.Assign(1);
shared_memory->system_properties.use_minus.Assign(1);
+ shared_memory->system_properties.is_charging_joy_dual.Assign(
+ battery_level.dual.is_charging);
shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController;
shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1);
break;
case Core::HID::NpadStyleIndex::Handheld:
+ shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
+ shared_memory->joycon_color.attribute = ColorAttribute::Ok;
+ shared_memory->fullkey_color.fullkey = body_colors.fullkey;
+ shared_memory->joycon_color.left = body_colors.left;
+ shared_memory->joycon_color.right = body_colors.right;
shared_memory->style_tag.handheld.Assign(1);
shared_memory->device_type.handheld_left.Assign(1);
shared_memory->device_type.handheld_right.Assign(1);
@@ -192,47 +215,86 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
shared_memory->system_properties.use_plus.Assign(1);
shared_memory->system_properties.use_minus.Assign(1);
shared_memory->system_properties.use_directional_buttons.Assign(1);
+ shared_memory->system_properties.is_charging_joy_dual.Assign(
+ battery_level.left.is_charging);
+ shared_memory->system_properties.is_charging_joy_left.Assign(
+ battery_level.left.is_charging);
+ shared_memory->system_properties.is_charging_joy_right.Assign(
+ battery_level.right.is_charging);
shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
shared_memory->applet_nfc_xcd.applet_footer.type =
AppletFooterUiType::HandheldJoyConLeftJoyConRight;
shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1);
break;
case Core::HID::NpadStyleIndex::JoyconDual:
+ shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
+ shared_memory->joycon_color.attribute = ColorAttribute::Ok;
shared_memory->style_tag.joycon_dual.Assign(1);
if (controller.is_dual_left_connected) {
+ shared_memory->joycon_color.left = body_colors.left;
+ shared_memory->battery_level_left = battery_level.left.battery_level;
shared_memory->device_type.joycon_left.Assign(1);
shared_memory->system_properties.use_minus.Assign(1);
+ shared_memory->system_properties.is_charging_joy_left.Assign(
+ battery_level.left.is_charging);
shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1);
}
if (controller.is_dual_right_connected) {
+ shared_memory->joycon_color.right = body_colors.right;
+ shared_memory->battery_level_right = battery_level.right.battery_level;
shared_memory->device_type.joycon_right.Assign(1);
shared_memory->system_properties.use_plus.Assign(1);
+ shared_memory->system_properties.is_charging_joy_right.Assign(
+ battery_level.right.is_charging);
shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1);
}
shared_memory->system_properties.use_directional_buttons.Assign(1);
shared_memory->system_properties.is_vertical.Assign(1);
shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
+
if (controller.is_dual_left_connected && controller.is_dual_right_connected) {
shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual;
+ shared_memory->fullkey_color.fullkey = body_colors.left;
+ shared_memory->battery_level_dual = battery_level.left.battery_level;
+ shared_memory->system_properties.is_charging_joy_dual.Assign(
+ battery_level.left.is_charging);
} else if (controller.is_dual_left_connected) {
shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly;
+ shared_memory->fullkey_color.fullkey = body_colors.left;
+ shared_memory->battery_level_dual = battery_level.left.battery_level;
+ shared_memory->system_properties.is_charging_joy_dual.Assign(
+ battery_level.left.is_charging);
} else {
shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly;
+ shared_memory->fullkey_color.fullkey = body_colors.right;
+ shared_memory->battery_level_dual = battery_level.right.battery_level;
+ shared_memory->system_properties.is_charging_joy_dual.Assign(
+ battery_level.right.is_charging);
}
break;
case Core::HID::NpadStyleIndex::JoyconLeft:
+ shared_memory->joycon_color.attribute = ColorAttribute::Ok;
+ shared_memory->joycon_color.left = body_colors.left;
+ shared_memory->battery_level_dual = battery_level.left.battery_level;
shared_memory->style_tag.joycon_left.Assign(1);
shared_memory->device_type.joycon_left.Assign(1);
shared_memory->system_properties.is_horizontal.Assign(1);
shared_memory->system_properties.use_minus.Assign(1);
+ shared_memory->system_properties.is_charging_joy_left.Assign(
+ battery_level.left.is_charging);
shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal;
shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1);
break;
case Core::HID::NpadStyleIndex::JoyconRight:
+ shared_memory->joycon_color.attribute = ColorAttribute::Ok;
+ shared_memory->joycon_color.right = body_colors.right;
+ shared_memory->battery_level_right = battery_level.right.battery_level;
shared_memory->style_tag.joycon_right.Assign(1);
shared_memory->device_type.joycon_right.Assign(1);
shared_memory->system_properties.is_horizontal.Assign(1);
shared_memory->system_properties.use_plus.Assign(1);
+ shared_memory->system_properties.is_charging_joy_right.Assign(
+ battery_level.right.is_charging);
shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal;
shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1);
break;
@@ -269,21 +331,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
break;
}
- const auto& body_colors = controller.device->GetColors();
-
- shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
- shared_memory->fullkey_color.fullkey = body_colors.fullkey;
-
- shared_memory->joycon_color.attribute = ColorAttribute::Ok;
- shared_memory->joycon_color.left = body_colors.left;
- shared_memory->joycon_color.right = body_colors.right;
-
- // TODO: Investigate when we should report all batery types
- const auto& battery_level = controller.device->GetBattery();
- shared_memory->battery_level_dual = battery_level.dual.battery_level;
- shared_memory->battery_level_left = battery_level.left.battery_level;
- shared_memory->battery_level_right = battery_level.right.battery_level;
-
controller.is_connected = true;
controller.device->Connect();
SignalStyleSetChangedEvent(npad_id);
diff --git a/src/core/hle/service/ldn/errors.h b/src/core/hle/service/ldn/errors.h
deleted file mode 100644
index 972a74806..000000000
--- a/src/core/hle/service/ldn/errors.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "core/hle/result.h"
-
-namespace Service::LDN {
-
-constexpr Result ERROR_DISABLED{ErrorModule::LDN, 22};
-
-} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index 125d4dc4c..c11daff54 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -3,11 +3,15 @@
#include <memory>
-#include "core/hle/ipc_helpers.h"
-#include "core/hle/result.h"
-#include "core/hle/service/ldn/errors.h"
+#include "core/core.h"
#include "core/hle/service/ldn/ldn.h"
-#include "core/hle/service/sm/sm.h"
+#include "core/hle/service/ldn/ldn_results.h"
+#include "core/hle/service/ldn/ldn_types.h"
+#include "core/internal_network/network.h"
+#include "core/internal_network/network_interface.h"
+
+// This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent
+#undef CreateEvent
namespace Service::LDN {
@@ -100,74 +104,418 @@ class IUserLocalCommunicationService final
: public ServiceFramework<IUserLocalCommunicationService> {
public:
explicit IUserLocalCommunicationService(Core::System& system_)
- : ServiceFramework{system_, "IUserLocalCommunicationService"} {
+ : ServiceFramework{system_, "IUserLocalCommunicationService", ServiceThreadType::CreateNew},
+ service_context{system, "IUserLocalCommunicationService"}, room_network{
+ system_.GetRoomNetwork()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IUserLocalCommunicationService::GetState, "GetState"},
- {1, nullptr, "GetNetworkInfo"},
+ {1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"},
{2, nullptr, "GetIpv4Address"},
- {3, nullptr, "GetDisconnectReason"},
- {4, nullptr, "GetSecurityParameter"},
- {5, nullptr, "GetNetworkConfig"},
- {100, nullptr, "AttachStateChangeEvent"},
- {101, nullptr, "GetNetworkInfoLatestUpdate"},
- {102, nullptr, "Scan"},
- {103, nullptr, "ScanPrivate"},
+ {3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"},
+ {4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"},
+ {5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"},
+ {100, &IUserLocalCommunicationService::AttachStateChangeEvent, "AttachStateChangeEvent"},
+ {101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"},
+ {102, &IUserLocalCommunicationService::Scan, "Scan"},
+ {103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"},
{104, nullptr, "SetWirelessControllerRestriction"},
- {200, nullptr, "OpenAccessPoint"},
- {201, nullptr, "CloseAccessPoint"},
- {202, nullptr, "CreateNetwork"},
- {203, nullptr, "CreateNetworkPrivate"},
- {204, nullptr, "DestroyNetwork"},
+ {200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"},
+ {201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"},
+ {202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"},
+ {203, &IUserLocalCommunicationService::CreateNetworkPrivate, "CreateNetworkPrivate"},
+ {204, &IUserLocalCommunicationService::DestroyNetwork, "DestroyNetwork"},
{205, nullptr, "Reject"},
- {206, nullptr, "SetAdvertiseData"},
- {207, nullptr, "SetStationAcceptPolicy"},
- {208, nullptr, "AddAcceptFilterEntry"},
+ {206, &IUserLocalCommunicationService::SetAdvertiseData, "SetAdvertiseData"},
+ {207, &IUserLocalCommunicationService::SetStationAcceptPolicy, "SetStationAcceptPolicy"},
+ {208, &IUserLocalCommunicationService::AddAcceptFilterEntry, "AddAcceptFilterEntry"},
{209, nullptr, "ClearAcceptFilter"},
- {300, nullptr, "OpenStation"},
- {301, nullptr, "CloseStation"},
- {302, nullptr, "Connect"},
+ {300, &IUserLocalCommunicationService::OpenStation, "OpenStation"},
+ {301, &IUserLocalCommunicationService::CloseStation, "CloseStation"},
+ {302, &IUserLocalCommunicationService::Connect, "Connect"},
{303, nullptr, "ConnectPrivate"},
- {304, nullptr, "Disconnect"},
- {400, nullptr, "Initialize"},
- {401, nullptr, "Finalize"},
- {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"}, // 7.0.0+
+ {304, &IUserLocalCommunicationService::Disconnect, "Disconnect"},
+ {400, &IUserLocalCommunicationService::Initialize, "Initialize"},
+ {401, &IUserLocalCommunicationService::Finalize, "Finalize"},
+ {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"},
};
// clang-format on
RegisterHandlers(functions);
+
+ state_change_event =
+ service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent");
+ }
+
+ ~IUserLocalCommunicationService() {
+ service_context.CloseEvent(state_change_event);
+ }
+
+ void OnEventFired() {
+ state_change_event->GetWritableEvent().Signal();
}
void GetState(Kernel::HLERequestContext& ctx) {
+ State state = State::Error;
+ LOG_WARNING(Service_LDN, "(STUBBED) called, state = {}", state);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(state);
+ }
+
+ void GetNetworkInfo(Kernel::HLERequestContext& ctx) {
+ const auto write_buffer_size = ctx.GetWriteBufferSize();
+
+ if (write_buffer_size != sizeof(NetworkInfo)) {
+ LOG_ERROR(Service_LDN, "Invalid buffer size {}", write_buffer_size);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultBadInput);
+ return;
+ }
+
+ NetworkInfo network_info{};
+ const auto rc = ResultSuccess;
+ if (rc.IsError()) {
+ LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(rc);
+ return;
+ }
+
+ LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}",
+ network_info.common.ssid.GetStringValue(), network_info.ldn.node_count);
+
+ ctx.WriteBuffer<NetworkInfo>(network_info);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(rc);
+ }
+
+ void GetDisconnectReason(Kernel::HLERequestContext& ctx) {
+ const auto disconnect_reason = DisconnectReason::None;
+
+ LOG_WARNING(Service_LDN, "(STUBBED) called, disconnect_reason={}", disconnect_reason);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(disconnect_reason);
+ }
+
+ void GetSecurityParameter(Kernel::HLERequestContext& ctx) {
+ SecurityParameter security_parameter{};
+ NetworkInfo info{};
+ const Result rc = ResultSuccess;
+
+ if (rc.IsError()) {
+ LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(rc);
+ return;
+ }
+
+ security_parameter.session_id = info.network_id.session_id;
+ std::memcpy(security_parameter.data.data(), info.ldn.security_parameter.data(),
+ sizeof(SecurityParameter::data));
+
LOG_WARNING(Service_LDN, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 10};
+ rb.Push(rc);
+ rb.PushRaw<SecurityParameter>(security_parameter);
+ }
+
+ void GetNetworkConfig(Kernel::HLERequestContext& ctx) {
+ NetworkConfig config{};
+ NetworkInfo info{};
+ const Result rc = ResultSuccess;
+
+ if (rc.IsError()) {
+ LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(rc);
+ return;
+ }
+
+ config.intent_id = info.network_id.intent_id;
+ config.channel = info.common.channel;
+ config.node_count_max = info.ldn.node_count_max;
+ config.local_communication_version = info.ldn.nodes[0].local_communication_version;
+
+ LOG_WARNING(Service_LDN,
+ "(STUBBED) called, intent_id={}/{}, channel={}, node_count_max={}, "
+ "local_communication_version={}",
+ config.intent_id.local_communication_id, config.intent_id.scene_id,
+ config.channel, config.node_count_max, config.local_communication_version);
+
+ IPC::ResponseBuilder rb{ctx, 10};
+ rb.Push(rc);
+ rb.PushRaw<NetworkConfig>(config);
+ }
+
+ void AttachStateChangeEvent(Kernel::HLERequestContext& ctx) {
+ LOG_INFO(Service_LDN, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(ResultSuccess);
+ rb.PushCopyObjects(state_change_event->GetReadableEvent());
+ }
+
+ void GetNetworkInfoLatestUpdate(Kernel::HLERequestContext& ctx) {
+ const std::size_t network_buffer_size = ctx.GetWriteBufferSize(0);
+ const std::size_t node_buffer_count = ctx.GetWriteBufferSize(1) / sizeof(NodeLatestUpdate);
+
+ if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) {
+ LOG_ERROR(Service_LDN, "Invalid buffer size {}, {}", network_buffer_size,
+ node_buffer_count);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultBadInput);
+ return;
+ }
+
+ NetworkInfo info;
+ std::vector<NodeLatestUpdate> latest_update(node_buffer_count);
+
+ const auto rc = ResultSuccess;
+ if (rc.IsError()) {
+ LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(rc);
+ return;
+ }
+
+ LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}",
+ info.common.ssid.GetStringValue(), info.ldn.node_count);
+
+ ctx.WriteBuffer(info, 0);
+ ctx.WriteBuffer(latest_update, 1);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void Scan(Kernel::HLERequestContext& ctx) {
+ ScanImpl(ctx);
+ }
+
+ void ScanPrivate(Kernel::HLERequestContext& ctx) {
+ ScanImpl(ctx, true);
+ }
+
+ void ScanImpl(Kernel::HLERequestContext& ctx, bool is_private = false) {
+ IPC::RequestParser rp{ctx};
+ const auto channel{rp.PopEnum<WifiChannel>()};
+ const auto scan_filter{rp.PopRaw<ScanFilter>()};
+
+ const std::size_t network_info_size = ctx.GetWriteBufferSize() / sizeof(NetworkInfo);
+
+ if (network_info_size == 0) {
+ LOG_ERROR(Service_LDN, "Invalid buffer size {}", network_info_size);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultBadInput);
+ return;
+ }
+
+ u16 count = 0;
+ std::vector<NetworkInfo> network_infos(network_info_size);
+
+ LOG_WARNING(Service_LDN,
+ "(STUBBED) called, channel={}, filter_scan_flag={}, filter_network_type={}",
+ channel, scan_filter.flag, scan_filter.network_type);
+
+ ctx.WriteBuffer(network_infos);
+
IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push<u32>(count);
+ }
+
+ void OpenAccessPoint(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void CloseAccessPoint(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void CreateNetwork(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ SecurityConfig security_config;
+ UserConfig user_config;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ NetworkConfig network_config;
+ };
+ static_assert(sizeof(Parameters) == 0x98, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_WARNING(Service_LDN,
+ "(STUBBED) called, passphrase_size={}, security_mode={}, "
+ "local_communication_version={}",
+ parameters.security_config.passphrase_size,
+ parameters.security_config.security_mode,
+ parameters.network_config.local_communication_version);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void CreateNetworkPrivate(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ SecurityConfig security_config;
+ SecurityParameter security_parameter;
+ UserConfig user_config;
+ NetworkConfig network_config;
+ };
+ static_assert(sizeof(Parameters) == 0xB8, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_WARNING(Service_LDN,
+ "(STUBBED) called, passphrase_size={}, security_mode={}, "
+ "local_communication_version={}",
+ parameters.security_config.passphrase_size,
+ parameters.security_config.security_mode,
+ parameters.network_config.local_communication_version);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void DestroyNetwork(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void SetAdvertiseData(Kernel::HLERequestContext& ctx) {
+ std::vector<u8> read_buffer = ctx.ReadBuffer();
+
+ LOG_WARNING(Service_LDN, "(STUBBED) called, size {}", read_buffer.size());
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void SetStationAcceptPolicy(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
- // Indicate a network error, as we do not actually emulate LDN
- rb.Push(static_cast<u32>(State::Error));
+ void AddAcceptFilterEntry(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void OpenStation(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void CloseStation(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void Connect(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ SecurityConfig security_config;
+ UserConfig user_config;
+ u32 local_communication_version;
+ u32 option;
+ };
+ static_assert(sizeof(Parameters) == 0x7C, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_WARNING(Service_LDN,
+ "(STUBBED) called, passphrase_size={}, security_mode={}, "
+ "local_communication_version={}",
+ parameters.security_config.passphrase_size,
+ parameters.security_config.security_mode,
+ parameters.local_communication_version);
+
+ const std::vector<u8> read_buffer = ctx.ReadBuffer();
+ NetworkInfo network_info{};
+
+ if (read_buffer.size() != sizeof(NetworkInfo)) {
+ LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultBadInput);
+ return;
+ }
+
+ std::memcpy(&network_info, read_buffer.data(), read_buffer.size());
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void Disconnect(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+ void Initialize(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
+
+ const auto rc = InitializeImpl(ctx);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(rc);
+ }
+
+ void Finalize(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
+
+ is_initialized = false;
+
+ IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Initialize2(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_LDN, "called");
+ LOG_WARNING(Service_LDN, "(STUBBED) called");
- is_initialized = true;
+ const auto rc = InitializeImpl(ctx);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_DISABLED);
+ rb.Push(rc);
+ }
+
+ Result InitializeImpl(Kernel::HLERequestContext& ctx) {
+ const auto network_interface = Network::GetSelectedNetworkInterface();
+ if (!network_interface) {
+ LOG_ERROR(Service_LDN, "No network interface is set");
+ return ResultAirplaneModeEnabled;
+ }
+
+ is_initialized = true;
+ // TODO (flTobi): Change this to ResultSuccess when LDN is fully implemented
+ return ResultAirplaneModeEnabled;
}
-private:
- enum class State {
- None,
- Initialized,
- AccessPointOpened,
- AccessPointCreated,
- StationOpened,
- StationConnected,
- Error,
- };
+ KernelHelpers::ServiceContext service_context;
+ Kernel::KEvent* state_change_event;
+ Network::RoomNetwork& room_network;
bool is_initialized{};
};
@@ -273,7 +621,7 @@ public:
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_DISABLED);
+ rb.Push(ResultDisabled);
}
};
diff --git a/src/core/hle/service/ldn/ldn.h b/src/core/hle/service/ldn/ldn.h
index a0031ac71..6afe2ea6f 100644
--- a/src/core/hle/service/ldn/ldn.h
+++ b/src/core/hle/service/ldn/ldn.h
@@ -3,6 +3,12 @@
#pragma once
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/result.h"
+#include "core/hle/service/kernel_helpers.h"
+#include "core/hle/service/sm/sm.h"
+
namespace Core {
class System;
}
diff --git a/src/core/hle/service/ldn/ldn_results.h b/src/core/hle/service/ldn/ldn_results.h
new file mode 100644
index 000000000..f340bda42
--- /dev/null
+++ b/src/core/hle/service/ldn/ldn_results.h
@@ -0,0 +1,27 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Service::LDN {
+
+constexpr Result ResultAdvertiseDataTooLarge{ErrorModule::LDN, 10};
+constexpr Result ResultAuthenticationFailed{ErrorModule::LDN, 20};
+constexpr Result ResultDisabled{ErrorModule::LDN, 22};
+constexpr Result ResultAirplaneModeEnabled{ErrorModule::LDN, 23};
+constexpr Result ResultInvalidNodeCount{ErrorModule::LDN, 30};
+constexpr Result ResultConnectionFailed{ErrorModule::LDN, 31};
+constexpr Result ResultBadState{ErrorModule::LDN, 32};
+constexpr Result ResultNoIpAddress{ErrorModule::LDN, 33};
+constexpr Result ResultInvalidBufferCount{ErrorModule::LDN, 50};
+constexpr Result ResultAccessPointConnectionFailed{ErrorModule::LDN, 65};
+constexpr Result ResultAuthenticationTimeout{ErrorModule::LDN, 66};
+constexpr Result ResultMaximumNodeCount{ErrorModule::LDN, 67};
+constexpr Result ResultBadInput{ErrorModule::LDN, 96};
+constexpr Result ResultLocalCommunicationIdNotFound{ErrorModule::LDN, 97};
+constexpr Result ResultLocalCommunicationVersionTooLow{ErrorModule::LDN, 113};
+constexpr Result ResultLocalCommunicationVersionTooHigh{ErrorModule::LDN, 114};
+
+} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h
new file mode 100644
index 000000000..0c07a7397
--- /dev/null
+++ b/src/core/hle/service/ldn/ldn_types.h
@@ -0,0 +1,284 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <fmt/format.h>
+
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "network/network.h"
+
+namespace Service::LDN {
+
+constexpr size_t SsidLengthMax = 32;
+constexpr size_t AdvertiseDataSizeMax = 384;
+constexpr size_t UserNameBytesMax = 32;
+constexpr int NodeCountMax = 8;
+constexpr int StationCountMax = NodeCountMax - 1;
+constexpr size_t PassphraseLengthMax = 64;
+
+enum class SecurityMode : u16 {
+ All,
+ Retail,
+ Debug,
+};
+
+enum class NodeStateChange : u8 {
+ None,
+ Connect,
+ Disconnect,
+ DisconnectAndConnect,
+};
+
+enum class ScanFilterFlag : u32 {
+ None = 0,
+ LocalCommunicationId = 1 << 0,
+ SessionId = 1 << 1,
+ NetworkType = 1 << 2,
+ Ssid = 1 << 4,
+ SceneId = 1 << 5,
+ IntentId = LocalCommunicationId | SceneId,
+ NetworkId = IntentId | SessionId,
+};
+
+enum class NetworkType : u32 {
+ None,
+ General,
+ Ldn,
+ All,
+};
+
+enum class PackedNetworkType : u8 {
+ None,
+ General,
+ Ldn,
+ All,
+};
+
+enum class State : u32 {
+ None,
+ Initialized,
+ AccessPointOpened,
+ AccessPointCreated,
+ StationOpened,
+ StationConnected,
+ Error,
+};
+
+enum class DisconnectReason : s16 {
+ Unknown = -1,
+ None,
+ DisconnectedByUser,
+ DisconnectedBySystem,
+ DestroyedByUser,
+ DestroyedBySystem,
+ Rejected,
+ SignalLost,
+};
+
+enum class NetworkError {
+ Unknown = -1,
+ None = 0,
+ PortUnreachable,
+ TooManyPlayers,
+ VersionTooLow,
+ VersionTooHigh,
+ ConnectFailure,
+ ConnectNotFound,
+ ConnectTimeout,
+ ConnectRejected,
+ RejectFailed,
+};
+
+enum class AcceptPolicy : u8 {
+ AcceptAll,
+ RejectAll,
+ BlackList,
+ WhiteList,
+};
+
+enum class WifiChannel : s16 {
+ Default = 0,
+ wifi24_1 = 1,
+ wifi24_6 = 6,
+ wifi24_11 = 11,
+ wifi50_36 = 36,
+ wifi50_40 = 40,
+ wifi50_44 = 44,
+ wifi50_48 = 48,
+};
+
+enum class LinkLevel : s8 {
+ Bad,
+ Low,
+ Good,
+ Excelent,
+};
+
+struct NodeLatestUpdate {
+ NodeStateChange state_change;
+ INSERT_PADDING_BYTES(0x7); // Unknown
+};
+static_assert(sizeof(NodeLatestUpdate) == 0x8, "NodeLatestUpdate is an invalid size");
+
+struct SessionId {
+ u64 high;
+ u64 low;
+
+ bool operator==(const SessionId&) const = default;
+};
+static_assert(sizeof(SessionId) == 0x10, "SessionId is an invalid size");
+
+struct IntentId {
+ u64 local_communication_id;
+ INSERT_PADDING_BYTES(0x2); // Reserved
+ u16 scene_id;
+ INSERT_PADDING_BYTES(0x4); // Reserved
+};
+static_assert(sizeof(IntentId) == 0x10, "IntentId is an invalid size");
+
+struct NetworkId {
+ IntentId intent_id;
+ SessionId session_id;
+};
+static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size");
+
+struct Ssid {
+ u8 length;
+ std::array<char, SsidLengthMax + 1> raw;
+
+ std::string GetStringValue() const {
+ return std::string(raw.data(), length);
+ }
+};
+static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size");
+
+struct Ipv4Address {
+ union {
+ u32 raw{};
+ std::array<u8, 4> bytes;
+ };
+
+ std::string GetStringValue() const {
+ return fmt::format("{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]);
+ }
+};
+static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size");
+
+struct MacAddress {
+ std::array<u8, 6> raw{};
+
+ friend bool operator==(const MacAddress& lhs, const MacAddress& rhs) = default;
+};
+static_assert(sizeof(MacAddress) == 0x6, "MacAddress is an invalid size");
+
+struct ScanFilter {
+ NetworkId network_id;
+ NetworkType network_type;
+ MacAddress mac_address;
+ Ssid ssid;
+ INSERT_PADDING_BYTES(0x10);
+ ScanFilterFlag flag;
+};
+static_assert(sizeof(ScanFilter) == 0x60, "ScanFilter is an invalid size");
+
+struct CommonNetworkInfo {
+ MacAddress bssid;
+ Ssid ssid;
+ WifiChannel channel;
+ LinkLevel link_level;
+ PackedNetworkType network_type;
+ INSERT_PADDING_BYTES(0x4);
+};
+static_assert(sizeof(CommonNetworkInfo) == 0x30, "CommonNetworkInfo is an invalid size");
+
+struct NodeInfo {
+ Ipv4Address ipv4_address;
+ MacAddress mac_address;
+ s8 node_id;
+ u8 is_connected;
+ std::array<u8, UserNameBytesMax + 1> user_name;
+ INSERT_PADDING_BYTES(0x1); // Reserved
+ s16 local_communication_version;
+ INSERT_PADDING_BYTES(0x10); // Reserved
+};
+static_assert(sizeof(NodeInfo) == 0x40, "NodeInfo is an invalid size");
+
+struct LdnNetworkInfo {
+ std::array<u8, 0x10> security_parameter;
+ SecurityMode security_mode;
+ AcceptPolicy station_accept_policy;
+ u8 has_action_frame;
+ INSERT_PADDING_BYTES(0x2); // Padding
+ u8 node_count_max;
+ u8 node_count;
+ std::array<NodeInfo, NodeCountMax> nodes;
+ INSERT_PADDING_BYTES(0x2); // Reserved
+ u16 advertise_data_size;
+ std::array<u8, AdvertiseDataSizeMax> advertise_data;
+ INSERT_PADDING_BYTES(0x8C); // Reserved
+ u64 random_authentication_id;
+};
+static_assert(sizeof(LdnNetworkInfo) == 0x430, "LdnNetworkInfo is an invalid size");
+
+struct NetworkInfo {
+ NetworkId network_id;
+ CommonNetworkInfo common;
+ LdnNetworkInfo ldn;
+};
+static_assert(sizeof(NetworkInfo) == 0x480, "NetworkInfo is an invalid size");
+
+struct SecurityConfig {
+ SecurityMode security_mode;
+ u16 passphrase_size;
+ std::array<u8, PassphraseLengthMax> passphrase;
+};
+static_assert(sizeof(SecurityConfig) == 0x44, "SecurityConfig is an invalid size");
+
+struct UserConfig {
+ std::array<u8, UserNameBytesMax + 1> user_name;
+ INSERT_PADDING_BYTES(0xF); // Reserved
+};
+static_assert(sizeof(UserConfig) == 0x30, "UserConfig is an invalid size");
+
+#pragma pack(push, 4)
+struct ConnectRequest {
+ SecurityConfig security_config;
+ UserConfig user_config;
+ u32 local_communication_version;
+ u32 option_unknown;
+ NetworkInfo network_info;
+};
+static_assert(sizeof(ConnectRequest) == 0x4FC, "ConnectRequest is an invalid size");
+#pragma pack(pop)
+
+struct SecurityParameter {
+ std::array<u8, 0x10> data; // Data, used with the same key derivation as SecurityConfig
+ SessionId session_id;
+};
+static_assert(sizeof(SecurityParameter) == 0x20, "SecurityParameter is an invalid size");
+
+struct NetworkConfig {
+ IntentId intent_id;
+ WifiChannel channel;
+ u8 node_count_max;
+ INSERT_PADDING_BYTES(0x1); // Reserved
+ u16 local_communication_version;
+ INSERT_PADDING_BYTES(0xA); // Reserved
+};
+static_assert(sizeof(NetworkConfig) == 0x20, "NetworkConfig is an invalid size");
+
+struct AddressEntry {
+ Ipv4Address ipv4_address;
+ MacAddress mac_address;
+ INSERT_PADDING_BYTES(0x2); // Reserved
+};
+static_assert(sizeof(AddressEntry) == 0xC, "AddressEntry is an invalid size");
+
+struct AddressList {
+ std::array<AddressEntry, 0x8> addresses;
+};
+static_assert(sizeof(AddressList) == 0x60, "AddressList is an invalid size");
+
+} // namespace Service::LDN
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 2889973e4..e3ef06481 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -6,7 +6,6 @@
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nifm/nifm.h"
-#include "core/hle/service/service.h"
namespace {
@@ -271,213 +270,228 @@ public:
}
};
-class IGeneralService final : public ServiceFramework<IGeneralService> {
-public:
- explicit IGeneralService(Core::System& system_);
+void IGeneralService::GetClientId(Kernel::HLERequestContext& ctx) {
+ static constexpr u32 client_id = 1;
+ LOG_WARNING(Service_NIFM, "(STUBBED) called");
-private:
- void GetClientId(Kernel::HLERequestContext& ctx) {
- static constexpr u32 client_id = 1;
- LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
+}
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
- }
+void IGeneralService::CreateScanRequest(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIFM, "called");
- void CreateScanRequest(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NIFM, "called");
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IScanRequest>(system);
+}
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IScanRequest>(system);
- }
+void IGeneralService::CreateRequest(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIFM, "called");
- void CreateRequest(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NIFM, "called");
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IRequest>(system);
+}
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IRequest>(system);
- }
+void IGeneralService::GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NIFM, "(STUBBED) called");
- void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ const auto net_iface = Network::GetSelectedNetworkInterface();
- const auto net_iface = Network::GetSelectedNetworkInterface();
-
- const SfNetworkProfileData network_profile_data = [&net_iface] {
- if (!net_iface) {
- return SfNetworkProfileData{};
- }
-
- return SfNetworkProfileData{
- .ip_setting_data{
- .ip_address_setting{
- .is_automatic{true},
- .current_address{Network::TranslateIPv4(net_iface->ip_address)},
- .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
- .gateway{Network::TranslateIPv4(net_iface->gateway)},
- },
- .dns_setting{
- .is_automatic{true},
- .primary_dns{1, 1, 1, 1},
- .secondary_dns{1, 0, 0, 1},
- },
- .proxy_setting{
- .enabled{false},
- .port{},
- .proxy_server{},
- .automatic_auth_enabled{},
- .user{},
- .password{},
- },
- .mtu{1500},
+ SfNetworkProfileData network_profile_data = [&net_iface] {
+ if (!net_iface) {
+ return SfNetworkProfileData{};
+ }
+
+ return SfNetworkProfileData{
+ .ip_setting_data{
+ .ip_address_setting{
+ .is_automatic{true},
+ .current_address{Network::TranslateIPv4(net_iface->ip_address)},
+ .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
+ .gateway{Network::TranslateIPv4(net_iface->gateway)},
},
- .uuid{0xdeadbeef, 0xdeadbeef},
- .network_name{"yuzu Network"},
- .wireless_setting_data{
- .ssid_length{12},
- .ssid{"yuzu Network"},
- .passphrase{"yuzupassword"},
+ .dns_setting{
+ .is_automatic{true},
+ .primary_dns{1, 1, 1, 1},
+ .secondary_dns{1, 0, 0, 1},
},
- };
- }();
-
- ctx.WriteBuffer(network_profile_data);
+ .proxy_setting{
+ .enabled{false},
+ .port{},
+ .proxy_server{},
+ .automatic_auth_enabled{},
+ .user{},
+ .password{},
+ },
+ .mtu{1500},
+ },
+ .uuid{0xdeadbeef, 0xdeadbeef},
+ .network_name{"yuzu Network"},
+ .wireless_setting_data{
+ .ssid_length{12},
+ .ssid{"yuzu Network"},
+ .passphrase{"yuzupassword"},
+ },
+ };
+ }();
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
+ // When we're connected to a room, spoof the hosts IP address
+ if (auto room_member = network.GetRoomMember().lock()) {
+ if (room_member->IsConnected()) {
+ network_profile_data.ip_setting_data.ip_address_setting.current_address =
+ room_member->GetFakeIpAddress();
+ }
}
- void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ ctx.WriteBuffer(network_profile_data);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
- void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NIFM, "(STUBBED) called");
+void IGeneralService::RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NIFM, "(STUBBED) called");
- auto ipv4 = Network::GetHostIPv4Address();
- if (!ipv4) {
- LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0");
- ipv4.emplace(Network::IPv4Address{0, 0, 0, 0});
- }
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushRaw(*ipv4);
+void IGeneralService::GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
+ auto ipv4 = Network::GetHostIPv4Address();
+ if (!ipv4) {
+ LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0");
+ ipv4.emplace(Network::IPv4Address{0, 0, 0, 0});
}
- void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
- LOG_DEBUG(Service_NIFM, "called");
+ // When we're connected to a room, spoof the hosts IP address
+ if (auto room_member = network.GetRoomMember().lock()) {
+ if (room_member->IsConnected()) {
+ ipv4 = room_member->GetFakeIpAddress();
+ }
+ }
- ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c,
- "SfNetworkProfileData is not the correct size");
- u128 uuid{};
- auto buffer = ctx.ReadBuffer();
- std::memcpy(&uuid, buffer.data() + 8, sizeof(u128));
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(*ipv4);
+}
- IPC::ResponseBuilder rb{ctx, 6, 0, 1};
+void IGeneralService::CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_NIFM, "called");
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<INetworkProfile>(system);
- rb.PushRaw<u128>(uuid);
- }
+ ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "SfNetworkProfileData is not the correct size");
+ u128 uuid{};
+ auto buffer = ctx.ReadBuffer();
+ std::memcpy(&uuid, buffer.data() + 8, sizeof(u128));
- void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 6, 0, 1};
- struct IpConfigInfo {
- IpAddressSetting ip_address_setting{};
- DnsSetting dns_setting{};
- };
- static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
- "IpConfigInfo has incorrect size.");
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<INetworkProfile>(system);
+ rb.PushRaw<u128>(uuid);
+}
- const auto net_iface = Network::GetSelectedNetworkInterface();
+void IGeneralService::GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NIFM, "(STUBBED) called");
- const IpConfigInfo ip_config_info = [&net_iface] {
- if (!net_iface) {
- return IpConfigInfo{};
- }
+ struct IpConfigInfo {
+ IpAddressSetting ip_address_setting{};
+ DnsSetting dns_setting{};
+ };
+ static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
+ "IpConfigInfo has incorrect size.");
- return IpConfigInfo{
- .ip_address_setting{
- .is_automatic{true},
- .current_address{Network::TranslateIPv4(net_iface->ip_address)},
- .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
- .gateway{Network::TranslateIPv4(net_iface->gateway)},
- },
- .dns_setting{
- .is_automatic{true},
- .primary_dns{1, 1, 1, 1},
- .secondary_dns{1, 0, 0, 1},
- },
- };
- }();
+ const auto net_iface = Network::GetSelectedNetworkInterface();
- IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)};
- rb.Push(ResultSuccess);
- rb.PushRaw<IpConfigInfo>(ip_config_info);
- }
+ IpConfigInfo ip_config_info = [&net_iface] {
+ if (!net_iface) {
+ return IpConfigInfo{};
+ }
- void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ return IpConfigInfo{
+ .ip_address_setting{
+ .is_automatic{true},
+ .current_address{Network::TranslateIPv4(net_iface->ip_address)},
+ .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
+ .gateway{Network::TranslateIPv4(net_iface->gateway)},
+ },
+ .dns_setting{
+ .is_automatic{true},
+ .primary_dns{1, 1, 1, 1},
+ .secondary_dns{1, 0, 0, 1},
+ },
+ };
+ }();
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u8>(0);
+ // When we're connected to a room, spoof the hosts IP address
+ if (auto room_member = network.GetRoomMember().lock()) {
+ if (room_member->IsConnected()) {
+ ip_config_info.ip_address_setting.current_address = room_member->GetFakeIpAddress();
+ }
}
- void GetInternetConnectionStatus(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)};
+ rb.Push(ResultSuccess);
+ rb.PushRaw<IpConfigInfo>(ip_config_info);
+}
- struct Output {
- InternetConnectionType type{InternetConnectionType::WiFi};
- u8 wifi_strength{3};
- InternetConnectionStatus state{InternetConnectionStatus::Connected};
- };
- static_assert(sizeof(Output) == 0x3, "Output has incorrect size.");
+void IGeneralService::IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NIFM, "(STUBBED) called");
- constexpr Output out{};
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push<u8>(1);
+}
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushRaw(out);
- }
+void IGeneralService::GetInternetConnectionStatus(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NIFM, "(STUBBED) called");
- void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NIFM, "(STUBBED) called");
+ struct Output {
+ InternetConnectionType type{InternetConnectionType::WiFi};
+ u8 wifi_strength{3};
+ InternetConnectionStatus state{InternetConnectionStatus::Connected};
+ };
+ static_assert(sizeof(Output) == 0x3, "Output has incorrect size.");
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- if (Network::GetHostIPv4Address().has_value()) {
- rb.Push<u8>(1);
- } else {
- rb.Push<u8>(0);
- }
+ constexpr Output out{};
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(out);
+}
+
+void IGeneralService::IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ if (Network::GetHostIPv4Address().has_value()) {
+ rb.Push<u8>(1);
+ } else {
+ rb.Push<u8>(0);
}
+}
- void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
- LOG_WARNING(Service_NIFM, "(STUBBED) called");
+void IGeneralService::IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
+ LOG_ERROR(Service_NIFM, "(STUBBED) called");
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- if (Network::GetHostIPv4Address().has_value()) {
- rb.Push<u8>(1);
- } else {
- rb.Push<u8>(0);
- }
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ if (Network::GetHostIPv4Address().has_value()) {
+ rb.Push<u8>(1);
+ } else {
+ rb.Push<u8>(0);
}
-};
+}
IGeneralService::IGeneralService(Core::System& system_)
- : ServiceFramework{system_, "IGeneralService"} {
+ : ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} {
// clang-format off
static const FunctionInfo functions[] = {
{1, &IGeneralService::GetClientId, "GetClientId"},
@@ -528,6 +542,8 @@ IGeneralService::IGeneralService(Core::System& system_)
RegisterHandlers(functions);
}
+IGeneralService::~IGeneralService() = default;
+
class NetworkInterface final : public ServiceFramework<NetworkInterface> {
public:
explicit NetworkInterface(const char* name, Core::System& system_)
diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h
index 5f62d0014..48161be28 100644
--- a/src/core/hle/service/nifm/nifm.h
+++ b/src/core/hle/service/nifm/nifm.h
@@ -3,6 +3,11 @@
#pragma once
+#include "core/hle/service/service.h"
+#include "network/network.h"
+#include "network/room.h"
+#include "network/room_member.h"
+
namespace Core {
class System;
}
@@ -16,4 +21,26 @@ namespace Service::NIFM {
/// Registers all NIFM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
+class IGeneralService final : public ServiceFramework<IGeneralService> {
+public:
+ explicit IGeneralService(Core::System& system_);
+ ~IGeneralService() override;
+
+private:
+ void GetClientId(Kernel::HLERequestContext& ctx);
+ void CreateScanRequest(Kernel::HLERequestContext& ctx);
+ void CreateRequest(Kernel::HLERequestContext& ctx);
+ void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx);
+ void RemoveNetworkProfile(Kernel::HLERequestContext& ctx);
+ void GetCurrentIpAddress(Kernel::HLERequestContext& ctx);
+ void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx);
+ void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx);
+ void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx);
+ void GetInternetConnectionStatus(Kernel::HLERequestContext& ctx);
+ void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx);
+ void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx);
+
+ Network::RoomNetwork& network;
+};
+
} // namespace Service::NIFM
diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp
index 0989474be..f7a497a14 100644
--- a/src/core/hle/service/pcv/pcv.cpp
+++ b/src/core/hle/service/pcv/pcv.cpp
@@ -3,6 +3,7 @@
#include <memory>
+#include "core/hle/ipc_helpers.h"
#include "core/hle/service/pcv/pcv.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -77,10 +78,102 @@ public:
}
};
+class IClkrstSession final : public ServiceFramework<IClkrstSession> {
+public:
+ explicit IClkrstSession(Core::System& system_, DeviceCode deivce_code_)
+ : ServiceFramework{system_, "IClkrstSession"}, deivce_code(deivce_code_) {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "SetClockEnabled"},
+ {1, nullptr, "SetClockDisabled"},
+ {2, nullptr, "SetResetAsserted"},
+ {3, nullptr, "SetResetDeasserted"},
+ {4, nullptr, "SetPowerEnabled"},
+ {5, nullptr, "SetPowerDisabled"},
+ {6, nullptr, "GetState"},
+ {7, &IClkrstSession::SetClockRate, "SetClockRate"},
+ {8, &IClkrstSession::GetClockRate, "GetClockRate"},
+ {9, nullptr, "SetMinVClockRate"},
+ {10, nullptr, "GetPossibleClockRates"},
+ {11, nullptr, "GetDvfsTable"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+ }
+
+private:
+ void SetClockRate(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ clock_rate = rp.Pop<u32>();
+ LOG_DEBUG(Service_PCV, "(STUBBED) called, clock_rate={}", clock_rate);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void GetClockRate(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_PCV, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push<u32>(clock_rate);
+ }
+
+ DeviceCode deivce_code;
+ u32 clock_rate{};
+};
+
+class CLKRST final : public ServiceFramework<CLKRST> {
+public:
+ explicit CLKRST(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &CLKRST::OpenSession, "OpenSession"},
+ {1, nullptr, "GetTemperatureThresholds"},
+ {2, nullptr, "SetTemperature"},
+ {3, nullptr, "GetModuleStateTable"},
+ {4, nullptr, "GetModuleStateTableEvent"},
+ {5, nullptr, "GetModuleStateTableMaxCount"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void OpenSession(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>());
+ const auto unkonwn_input = rp.Pop<u32>();
+
+ LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unkonwn_input);
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IClkrstSession>(system, device_code);
+ }
+};
+
+class CLKRST_A final : public ServiceFramework<CLKRST_A> {
+public:
+ explicit CLKRST_A(Core::System& system_) : ServiceFramework{system_, "clkrst:a"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "ReleaseControl"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+};
+
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
std::make_shared<PCV>(system)->InstallAsService(sm);
std::make_shared<PCV_ARB>(system)->InstallAsService(sm);
std::make_shared<PCV_IMM>(system)->InstallAsService(sm);
+ std::make_shared<CLKRST>(system, "clkrst")->InstallAsService(sm);
+ std::make_shared<CLKRST>(system, "clkrst:i")->InstallAsService(sm);
+ std::make_shared<CLKRST_A>(system)->InstallAsService(sm);
}
} // namespace Service::PCV
diff --git a/src/core/hle/service/pcv/pcv.h b/src/core/hle/service/pcv/pcv.h
index a42e6f8f6..6b26b6fa7 100644
--- a/src/core/hle/service/pcv/pcv.h
+++ b/src/core/hle/service/pcv/pcv.h
@@ -13,6 +13,97 @@ class ServiceManager;
namespace Service::PCV {
+enum class DeviceCode : u32 {
+ Cpu = 0x40000001,
+ Gpu = 0x40000002,
+ I2s1 = 0x40000003,
+ I2s2 = 0x40000004,
+ I2s3 = 0x40000005,
+ Pwm = 0x40000006,
+ I2c1 = 0x02000001,
+ I2c2 = 0x02000002,
+ I2c3 = 0x02000003,
+ I2c4 = 0x02000004,
+ I2c5 = 0x02000005,
+ I2c6 = 0x02000006,
+ Spi1 = 0x07000000,
+ Spi2 = 0x07000001,
+ Spi3 = 0x07000002,
+ Spi4 = 0x07000003,
+ Disp1 = 0x40000011,
+ Disp2 = 0x40000012,
+ Isp = 0x40000013,
+ Vi = 0x40000014,
+ Sdmmc1 = 0x40000015,
+ Sdmmc2 = 0x40000016,
+ Sdmmc3 = 0x40000017,
+ Sdmmc4 = 0x40000018,
+ Owr = 0x40000019,
+ Csite = 0x4000001A,
+ Tsec = 0x4000001B,
+ Mselect = 0x4000001C,
+ Hda2codec2x = 0x4000001D,
+ Actmon = 0x4000001E,
+ I2cSlow = 0x4000001F,
+ Sor1 = 0x40000020,
+ Sata = 0x40000021,
+ Hda = 0x40000022,
+ XusbCoreHostSrc = 0x40000023,
+ XusbFalconSrc = 0x40000024,
+ XusbFsSrc = 0x40000025,
+ XusbCoreDevSrc = 0x40000026,
+ XusbSsSrc = 0x40000027,
+ UartA = 0x03000001,
+ UartB = 0x35000405,
+ UartC = 0x3500040F,
+ UartD = 0x37000001,
+ Host1x = 0x4000002C,
+ Entropy = 0x4000002D,
+ SocTherm = 0x4000002E,
+ Vic = 0x4000002F,
+ Nvenc = 0x40000030,
+ Nvjpg = 0x40000031,
+ Nvdec = 0x40000032,
+ Qspi = 0x40000033,
+ ViI2c = 0x40000034,
+ Tsecb = 0x40000035,
+ Ape = 0x40000036,
+ AudioDsp = 0x40000037,
+ AudioUart = 0x40000038,
+ Emc = 0x40000039,
+ Plle = 0x4000003A,
+ PlleHwSeq = 0x4000003B,
+ Dsi = 0x4000003C,
+ Maud = 0x4000003D,
+ Dpaux1 = 0x4000003E,
+ MipiCal = 0x4000003F,
+ UartFstMipiCal = 0x40000040,
+ Osc = 0x40000041,
+ SysBus = 0x40000042,
+ SorSafe = 0x40000043,
+ XusbSs = 0x40000044,
+ XusbHost = 0x40000045,
+ XusbDevice = 0x40000046,
+ Extperiph1 = 0x40000047,
+ Ahub = 0x40000048,
+ Hda2hdmicodec = 0x40000049,
+ Gpuaux = 0x4000004A,
+ UsbD = 0x4000004B,
+ Usb2 = 0x4000004C,
+ Pcie = 0x4000004D,
+ Afi = 0x4000004E,
+ PciExClk = 0x4000004F,
+ PExUsbPhy = 0x40000050,
+ XUsbPadCtl = 0x40000051,
+ Apbdma = 0x40000052,
+ Usb2TrkClk = 0x40000053,
+ XUsbIoPll = 0x40000054,
+ XUsbIoPllHwSeq = 0x40000055,
+ Cec = 0x40000056,
+ Extperiph2 = 0x40000057,
+ OscClk = 0x40000080
+};
+
void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
} // namespace Service::PCV
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index c64291e7f..dadaf897f 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -194,13 +194,16 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
Kernel::HLERequestContext& ctx) {
const auto guard = LockService();
+ Result result = ResultSuccess;
+
switch (ctx.GetCommandType()) {
case IPC::CommandType::Close:
case IPC::CommandType::TIPC_Close: {
session.Close();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
- return IPC::ERR_REMOTE_PROCESS_DEAD;
+ result = IPC::ERR_REMOTE_PROCESS_DEAD;
+ break;
}
case IPC::CommandType::ControlWithContext:
case IPC::CommandType::Control: {
@@ -227,7 +230,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
ctx.WriteToOutgoingCommandBuffer(ctx.GetThread());
}
- return ResultSuccess;
+ return result;
}
/// Initialize Services
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index c7194731e..e08c3cb67 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -9,12 +9,16 @@
#include <fmt/format.h>
#include "common/microprofile.h"
+#include "common/socket_types.h"
+#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/service/sockets/bsd.h"
#include "core/hle/service/sockets/sockets_translate.h"
#include "core/internal_network/network.h"
+#include "core/internal_network/socket_proxy.h"
#include "core/internal_network/sockets.h"
+#include "network/network.h"
namespace Service::Sockets {
@@ -472,7 +476,13 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
LOG_INFO(Service, "New socket fd={}", fd);
- descriptor.socket = std::make_unique<Network::Socket>();
+ auto room_member = room_network.GetRoomMember().lock();
+ if (room_member && room_member->IsConnected()) {
+ descriptor.socket = std::make_unique<Network::ProxySocket>(room_network);
+ } else {
+ descriptor.socket = std::make_unique<Network::Socket>();
+ }
+
descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(type, protocol));
descriptor.is_connection_based = IsConnectionBased(type);
@@ -648,7 +658,7 @@ std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
ASSERT(arg == 0);
return {descriptor.flags, Errno::SUCCESS};
case FcntlCmd::SETFL: {
- const bool enable = (arg & FLAG_O_NONBLOCK) != 0;
+ const bool enable = (arg & Network::FLAG_O_NONBLOCK) != 0;
const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable));
if (bsd_errno != Errno::SUCCESS) {
return {-1, bsd_errno};
@@ -669,7 +679,7 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con
return Errno::BADF;
}
- Network::Socket* const socket = file_descriptors[fd]->socket.get();
+ Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
if (optname == OptName::LINGER) {
ASSERT(optlen == sizeof(Linger));
@@ -724,6 +734,8 @@ std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message)
FileDescriptor& descriptor = *file_descriptors[fd];
// Apply flags
+ using Network::FLAG_MSG_DONTWAIT;
+ using Network::FLAG_O_NONBLOCK;
if ((flags & FLAG_MSG_DONTWAIT) != 0) {
flags &= ~FLAG_MSG_DONTWAIT;
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
@@ -759,6 +771,8 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
}
// Apply flags
+ using Network::FLAG_MSG_DONTWAIT;
+ using Network::FLAG_O_NONBLOCK;
if ((flags & FLAG_MSG_DONTWAIT) != 0) {
flags &= ~FLAG_MSG_DONTWAIT;
if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
@@ -857,8 +871,19 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co
rb.PushEnum(bsd_errno);
}
+void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
+ for (auto& optional_descriptor : file_descriptors) {
+ if (!optional_descriptor.has_value()) {
+ continue;
+ }
+ FileDescriptor& descriptor = *optional_descriptor;
+ descriptor.socket.get()->HandleProxyPacket(packet);
+ }
+}
+
BSD::BSD(Core::System& system_, const char* name)
- : ServiceFramework{system_, name, ServiceThreadType::CreateNew} {
+ : ServiceFramework{system_, name, ServiceThreadType::CreateNew}, room_network{
+ system_.GetRoomNetwork()} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &BSD::RegisterClient, "RegisterClient"},
@@ -899,6 +924,13 @@ BSD::BSD(Core::System& system_, const char* name)
// clang-format on
RegisterHandlers(functions);
+
+ if (auto room_member = room_network.GetRoomMember().lock()) {
+ proxy_packet_received = room_member->BindOnProxyPacketReceived(
+ [this](const Network::ProxyPacket& packet) { OnProxyPacketReceived(packet); });
+ } else {
+ LOG_ERROR(Service, "Network isn't initalized");
+ }
}
BSD::~BSD() = default;
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 9ea36428d..81e855e0f 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -7,14 +7,17 @@
#include <vector>
#include "common/common_types.h"
+#include "common/socket_types.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sockets/sockets.h"
+#include "network/network.h"
namespace Core {
class System;
}
namespace Network {
+class SocketBase;
class Socket;
} // namespace Network
@@ -30,7 +33,7 @@ private:
static constexpr size_t MAX_FD = 128;
struct FileDescriptor {
- std::unique_ptr<Network::Socket> socket;
+ std::unique_ptr<Network::SocketBase> socket;
s32 flags = 0;
bool is_connection_based = false;
};
@@ -165,6 +168,14 @@ private:
void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept;
std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors;
+
+ Network::RoomNetwork& room_network;
+
+ /// Callback to parse and handle a received wifi packet.
+ void OnProxyPacketReceived(const Network::ProxyPacket& packet);
+
+ // Callback identifier for the OnProxyPacketReceived event.
+ Network::RoomMember::CallbackHandle<Network::ProxyPacket> proxy_packet_received;
};
class BSDCFG final : public ServiceFramework<BSDCFG> {
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index b735b00fc..31b7dad33 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -22,7 +22,9 @@ enum class Errno : u32 {
AGAIN = 11,
INVAL = 22,
MFILE = 24,
+ MSGSIZE = 90,
NOTCONN = 107,
+ TIMEDOUT = 110,
};
enum class Domain : u32 {
@@ -96,10 +98,6 @@ struct Linger {
u32 linger;
};
-constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
-
-constexpr u32 FLAG_O_NONBLOCK = 0x800;
-
/// Registers all Sockets services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp
index 2db10ec81..023aa0486 100644
--- a/src/core/hle/service/sockets/sockets_translate.cpp
+++ b/src/core/hle/service/sockets/sockets_translate.cpp
@@ -25,6 +25,8 @@ Errno Translate(Network::Errno value) {
return Errno::MFILE;
case Network::Errno::NOTCONN:
return Errno::NOTCONN;
+ case Network::Errno::TIMEDOUT:
+ return Errno::TIMEDOUT;
default:
UNIMPLEMENTED_MSG("Unimplemented errno={}", value);
return Errno::SUCCESS;