diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-11-02 22:52:39 +0100 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-11-02 23:00:10 +0100 |
| commit | 693529b27ec898b867ad5806a0174f69597decc9 (patch) | |
| tree | f7e803a5b877be4353f1ff2368bb230180b7383f /src | |
| parent | 8aafca259892d2f3d573ae4890470bdb7cfc62a8 (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.cpp | 22 |
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); |
