aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-11-02 22:52:39 +0100
committercirakg <cirakg@cirakg.xyz>2026-11-02 23:00:10 +0100
commit693529b27ec898b867ad5806a0174f69597decc9 (patch)
treef7e803a5b877be4353f1ff2368bb230180b7383f /src
parent8aafca259892d2f3d573ae4890470bdb7cfc62a8 (diff)
nifm: treat a joined room as the LAN for local network games
LAN Play through public lobby rooms failed in two ways. With airplane mode on (the default), IRequest::GetResult rejected the game's network request. Mario Kart World then opened the net-connect applet and returned to the main menu instead of the LAN browser. A joined room is the emulated network: its sockets only reach room members. Count it as an available network for GetResult and IsAnyInternetRequestAccepted. With airplane mode off, players could open the browser but never saw each other. Room fake IPs are spread over 192.168.0.0/16, and some room servers give members different /24s. NIFM reported the host adapter's /24 mask with the fake IP, so the games treated each other as off-subnet. Report 255.255.0.0 in a room instead. Assisted-by: Claude Opus 5.5 (investigation and implementation)
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/service/nifm/nifm.cpp22
1 files changed, 19 insertions, 3 deletions
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index efada9b807..153b0f2193 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -70,6 +70,20 @@ static u128 MakeUuidFromName(std::string_view name) {
return {h1, h2};
}
+// A joined room is the emulated network, even in airplane mode. Its sockets only reach room
+// members, and LAN games (e.g. Mario Kart World LAN Play) need their connection request accepted.
+static bool IsNetworkAvailable() {
+ if (const auto room_member = Network::GetRoomMember().lock();
+ room_member && room_member->GetState() == Network::RoomMember::State::Joined) {
+ return true;
+ }
+ return Network::GetHostIPv4Address().has_value() && !Settings::values.airplane_mode.GetValue();
+}
+
+// Room fake IPs are spread over 192.168.0.0/16, and some room servers give members different /24s.
+// A host /24 mask would then put room members on different subnets, so LAN games ignore each other.
+constexpr Network::IPv4Address RoomSubnetMask{255, 255, 0, 0};
+
// This is nn::nifm::RequestState
enum class RequestState : u32 {
NotSubmitted = 1,
@@ -430,8 +444,7 @@ private:
LOG_DEBUG(Service_NIFM, "(STUBBED) called");
const auto result = [this] {
- const auto has_connection = Network::GetHostIPv4Address().has_value() &&
- !Settings::values.airplane_mode.GetValue();
+ const auto has_connection = IsNetworkAvailable();
switch (state) {
case RequestState::NotSubmitted:
return has_connection ? ResultSuccess : ResultNetworkCommunicationDisabled;
@@ -575,6 +588,7 @@ void IGeneralService::GetCurrentNetworkProfile(HLERequestContext& ctx) {
if (room_member->IsConnected()) {
profile.ip_setting_data.ip_address_setting.ip_address =
room_member->GetFakeIpAddress();
+ profile.ip_setting_data.ip_address_setting.subnet_mask = RoomSubnetMask;
}
profile.ip_setting_data.dns_setting.secondary_dns = {8, 8, 8, 8};
}
@@ -714,6 +728,7 @@ void IGeneralService::GetNetworkProfile(HLERequestContext& ctx) {
if (auto room_member = Network::GetRoomMember().lock()) {
if (room_member->IsConnected()) {
profile.ip_setting_data.ip_address_setting.ip_address = room_member->GetFakeIpAddress();
+ profile.ip_setting_data.ip_address_setting.subnet_mask = RoomSubnetMask;
}
}
@@ -904,6 +919,7 @@ void IGeneralService::GetCurrentIpConfigInfo(HLERequestContext& ctx) {
if (auto room_member = Network::GetRoomMember().lock()) {
if (room_member->IsConnected()) {
info.ip.ip_address = room_member->GetFakeIpAddress();
+ info.ip.subnet_mask = RoomSubnetMask;
}
info.dns.is_automatic = true;
info.dns.primary_dns = {1, 1, 1, 1};
@@ -984,7 +1000,7 @@ void IGeneralService::IsAnyInternetRequestAccepted(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
- if (Network::GetHostIPv4Address().has_value() && !Settings::values.airplane_mode.GetValue()) {
+ if (IsNetworkAvailable()) {
rb.Push<u8>(1);
} else {
rb.Push<u8>(0);