summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar liamwhite2024-02-13 08:18:31 -0500
committerGravatar GitHub2024-02-13 08:18:31 -0500
commit95d96cfe663aadedf86ce2b8bd2dfc132463b819 (patch)
tree04c9140090ff20b178c31bd567df9883b0647f58
parentMerge pull request #12975 from FernandoS27/keep-your-own-vodoo-doll-away-from-gf (diff)
parentservice: ldn: Migrate and refractor service to new IPC (diff)
downloadyuzu-95d96cfe663aadedf86ce2b8bd2dfc132463b819.tar.gz
yuzu-95d96cfe663aadedf86ce2b8bd2dfc132463b819.tar.xz
yuzu-95d96cfe663aadedf86ce2b8bd2dfc132463b819.zip
Merge pull request #12974 from german77/ldn-interface
service: ldn: Migrate and refractor service to new IPC
Diffstat (limited to '')
-rw-r--r--src/core/CMakeLists.txt12
-rw-r--r--src/core/hle/service/ldn/lan_discovery.cpp20
-rw-r--r--src/core/hle/service/ldn/lan_discovery.h5
-rw-r--r--src/core/hle/service/ldn/ldn.cpp802
-rw-r--r--src/core/hle/service/ldn/ldn.h6
-rw-r--r--src/core/hle/service/ldn/ldn_types.h68
-rw-r--r--src/core/hle/service/ldn/monitor_service.cpp43
-rw-r--r--src/core/hle/service/ldn/monitor_service.h28
-rw-r--r--src/core/hle/service/ldn/sf_monitor_service.cpp40
-rw-r--r--src/core/hle/service/ldn/sf_monitor_service.h26
-rw-r--r--src/core/hle/service/ldn/sf_service.cpp37
-rw-r--r--src/core/hle/service/ldn/sf_service.h21
-rw-r--r--src/core/hle/service/ldn/sf_service_monitor.cpp50
-rw-r--r--src/core/hle/service/ldn/sf_service_monitor.h26
-rw-r--r--src/core/hle/service/ldn/system_local_communication_service.cpp56
-rw-r--r--src/core/hle/service/ldn/system_local_communication_service.h25
-rw-r--r--src/core/hle/service/ldn/user_local_communication_service.cpp320
-rw-r--r--src/core/hle/service/ldn/user_local_communication_service.h103
18 files changed, 910 insertions, 778 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 2d5490968..175ff8824 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -668,6 +668,18 @@ add_library(core STATIC
668 hle/service/ldn/ldn.h 668 hle/service/ldn/ldn.h
669 hle/service/ldn/ldn_results.h 669 hle/service/ldn/ldn_results.h
670 hle/service/ldn/ldn_types.h 670 hle/service/ldn/ldn_types.h
671 hle/service/ldn/monitor_service.cpp
672 hle/service/ldn/monitor_service.h
673 hle/service/ldn/sf_monitor_service.cpp
674 hle/service/ldn/sf_monitor_service.h
675 hle/service/ldn/sf_service.cpp
676 hle/service/ldn/sf_service.h
677 hle/service/ldn/sf_service_monitor.cpp
678 hle/service/ldn/sf_service_monitor.h
679 hle/service/ldn/system_local_communication_service.cpp
680 hle/service/ldn/system_local_communication_service.h
681 hle/service/ldn/user_local_communication_service.cpp
682 hle/service/ldn/user_local_communication_service.h
671 hle/service/ldr/ldr.cpp 683 hle/service/ldr/ldr.cpp
672 hle/service/ldr/ldr.h 684 hle/service/ldr/ldr.h
673 hle/service/lm/lm.cpp 685 hle/service/lm/lm.cpp
diff --git a/src/core/hle/service/ldn/lan_discovery.cpp b/src/core/hle/service/ldn/lan_discovery.cpp
index 8f3c04550..b9db19618 100644
--- a/src/core/hle/service/ldn/lan_discovery.cpp
+++ b/src/core/hle/service/ldn/lan_discovery.cpp
@@ -85,15 +85,14 @@ Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network) const {
85} 85}
86 86
87Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network, 87Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network,
88 std::vector<NodeLatestUpdate>& out_updates, 88 std::span<NodeLatestUpdate> out_updates) {
89 std::size_t buffer_count) { 89 if (out_updates.size() > NodeCountMax) {
90 if (buffer_count > NodeCountMax) {
91 return ResultInvalidBufferCount; 90 return ResultInvalidBufferCount;
92 } 91 }
93 92
94 if (state == State::AccessPointCreated || state == State::StationConnected) { 93 if (state == State::AccessPointCreated || state == State::StationConnected) {
95 std::memcpy(&out_network, &network_info, sizeof(network_info)); 94 std::memcpy(&out_network, &network_info, sizeof(network_info));
96 for (std::size_t i = 0; i < buffer_count; i++) { 95 for (std::size_t i = 0; i < out_updates.size(); i++) {
97 out_updates[i].state_change = node_changes[i].state_change; 96 out_updates[i].state_change = node_changes[i].state_change;
98 node_changes[i].state_change = NodeStateChange::None; 97 node_changes[i].state_change = NodeStateChange::None;
99 } 98 }
@@ -107,15 +106,8 @@ DisconnectReason LANDiscovery::GetDisconnectReason() const {
107 return disconnect_reason; 106 return disconnect_reason;
108} 107}
109 108
110Result LANDiscovery::Scan(std::vector<NetworkInfo>& networks, u16& count, 109Result LANDiscovery::Scan(std::span<NetworkInfo> out_networks, s16& out_count,
111 const ScanFilter& filter) { 110 const ScanFilter& filter) {
112 if (!IsFlagSet(filter.flag, ScanFilterFlag::NetworkType) ||
113 filter.network_type <= NetworkType::All) {
114 if (!IsFlagSet(filter.flag, ScanFilterFlag::Ssid) && filter.ssid.length >= SsidLengthMax) {
115 return ResultBadInput;
116 }
117 }
118
119 { 111 {
120 std::scoped_lock lock{packet_mutex}; 112 std::scoped_lock lock{packet_mutex};
121 scan_results.clear(); 113 scan_results.clear();
@@ -128,7 +120,7 @@ Result LANDiscovery::Scan(std::vector<NetworkInfo>& networks, u16& count,
128 120
129 std::scoped_lock lock{packet_mutex}; 121 std::scoped_lock lock{packet_mutex};
130 for (const auto& [key, info] : scan_results) { 122 for (const auto& [key, info] : scan_results) {
131 if (count >= networks.size()) { 123 if (out_count >= static_cast<s16>(out_networks.size())) {
132 break; 124 break;
133 } 125 }
134 126
@@ -159,7 +151,7 @@ Result LANDiscovery::Scan(std::vector<NetworkInfo>& networks, u16& count,
159 } 151 }
160 } 152 }
161 153
162 networks[count++] = info; 154 out_networks[out_count++] = info;
163 } 155 }
164 156
165 return ResultSuccess; 157 return ResultSuccess;
diff --git a/src/core/hle/service/ldn/lan_discovery.h b/src/core/hle/service/ldn/lan_discovery.h
index 3833cd764..8f7a8dfc4 100644
--- a/src/core/hle/service/ldn/lan_discovery.h
+++ b/src/core/hle/service/ldn/lan_discovery.h
@@ -54,11 +54,10 @@ public:
54 void SetState(State new_state); 54 void SetState(State new_state);
55 55
56 Result GetNetworkInfo(NetworkInfo& out_network) const; 56 Result GetNetworkInfo(NetworkInfo& out_network) const;
57 Result GetNetworkInfo(NetworkInfo& out_network, std::vector<NodeLatestUpdate>& out_updates, 57 Result GetNetworkInfo(NetworkInfo& out_network, std::span<NodeLatestUpdate> out_updates);
58 std::size_t buffer_count);
59 58
60 DisconnectReason GetDisconnectReason() const; 59 DisconnectReason GetDisconnectReason() const;
61 Result Scan(std::vector<NetworkInfo>& networks, u16& count, const ScanFilter& filter); 60 Result Scan(std::span<NetworkInfo> out_networks, s16& out_count, const ScanFilter& filter);
62 Result SetAdvertiseData(std::span<const u8> data); 61 Result SetAdvertiseData(std::span<const u8> data);
63 62
64 Result OpenAccessPoint(); 63 Result OpenAccessPoint();
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index 961f89a14..f2d638c30 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -1,36 +1,24 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <memory>
5
6#include "core/core.h" 4#include "core/core.h"
7#include "core/hle/service/ldn/lan_discovery.h" 5#include "core/hle/service/cmif_serialization.h"
8#include "core/hle/service/ldn/ldn.h" 6#include "core/hle/service/ldn/ldn.h"
9#include "core/hle/service/ldn/ldn_results.h" 7#include "core/hle/service/ldn/monitor_service.h"
10#include "core/hle/service/ldn/ldn_types.h" 8#include "core/hle/service/ldn/sf_monitor_service.h"
11#include "core/hle/service/server_manager.h" 9#include "core/hle/service/ldn/sf_service.h"
12#include "core/internal_network/network.h" 10#include "core/hle/service/ldn/sf_service_monitor.h"
13#include "core/internal_network/network_interface.h" 11#include "core/hle/service/ldn/system_local_communication_service.h"
14#include "network/network.h" 12#include "core/hle/service/ldn/user_local_communication_service.h"
15
16// This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent
17#undef CreateEvent
18 13
19namespace Service::LDN { 14namespace Service::LDN {
20 15
21class IMonitorService final : public ServiceFramework<IMonitorService> { 16class IMonitorServiceCreator final : public ServiceFramework<IMonitorServiceCreator> {
22public: 17public:
23 explicit IMonitorService(Core::System& system_) : ServiceFramework{system_, "IMonitorService"} { 18 explicit IMonitorServiceCreator(Core::System& system_) : ServiceFramework{system_, "ldn:m"} {
24 // clang-format off 19 // clang-format off
25 static const FunctionInfo functions[] = { 20 static const FunctionInfo functions[] = {
26 {0, &IMonitorService::GetStateForMonitor, "GetStateForMonitor"}, 21 {0, C<&IMonitorServiceCreator::CreateMonitorService>, "CreateMonitorService"}
27 {1, nullptr, "GetNetworkInfoForMonitor"},
28 {2, nullptr, "GetIpv4AddressForMonitor"},
29 {3, nullptr, "GetDisconnectReasonForMonitor"},
30 {4, nullptr, "GetSecurityParameterForMonitor"},
31 {5, nullptr, "GetNetworkConfigForMonitor"},
32 {100, &IMonitorService::InitializeMonitor, "InitializeMonitor"},
33 {101, nullptr, "FinalizeMonitor"},
34 }; 22 };
35 // clang-format on 23 // clang-format on
36 24
@@ -38,84 +26,20 @@ public:
38 } 26 }
39 27
40private: 28private:
41 void GetStateForMonitor(HLERequestContext& ctx) { 29 Result CreateMonitorService(OutInterface<IMonitorService> out_interface) {
42 LOG_INFO(Service_LDN, "called");
43
44 IPC::ResponseBuilder rb{ctx, 3};
45 rb.Push(ResultSuccess);
46 rb.PushEnum(state);
47 }
48
49 void InitializeMonitor(HLERequestContext& ctx) {
50 LOG_INFO(Service_LDN, "called");
51
52 state = State::Initialized;
53
54 IPC::ResponseBuilder rb{ctx, 2};
55 rb.Push(ResultSuccess);
56 }
57
58 State state{State::None};
59};
60
61class LDNM final : public ServiceFramework<LDNM> {
62public:
63 explicit LDNM(Core::System& system_) : ServiceFramework{system_, "ldn:m"} {
64 // clang-format off
65 static const FunctionInfo functions[] = {
66 {0, &LDNM::CreateMonitorService, "CreateMonitorService"}
67 };
68 // clang-format on
69
70 RegisterHandlers(functions);
71 }
72
73 void CreateMonitorService(HLERequestContext& ctx) {
74 LOG_DEBUG(Service_LDN, "called"); 30 LOG_DEBUG(Service_LDN, "called");
75 31
76 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 32 *out_interface = std::make_shared<IMonitorService>(system);
77 rb.Push(ResultSuccess); 33 R_SUCCEED();
78 rb.PushIpcInterface<IMonitorService>(system);
79 } 34 }
80}; 35};
81 36
82class ISystemLocalCommunicationService final 37class ISystemServiceCreator final : public ServiceFramework<ISystemServiceCreator> {
83 : public ServiceFramework<ISystemLocalCommunicationService> {
84public: 38public:
85 explicit ISystemLocalCommunicationService(Core::System& system_) 39 explicit ISystemServiceCreator(Core::System& system_) : ServiceFramework{system_, "ldn:s"} {
86 : ServiceFramework{system_, "ISystemLocalCommunicationService"} {
87 // clang-format off 40 // clang-format off
88 static const FunctionInfo functions[] = { 41 static const FunctionInfo functions[] = {
89 {0, nullptr, "GetState"}, 42 {0, C<&ISystemServiceCreator::CreateSystemLocalCommunicationService>, "CreateSystemLocalCommunicationService"},
90 {1, nullptr, "GetNetworkInfo"},
91 {2, nullptr, "GetIpv4Address"},
92 {3, nullptr, "GetDisconnectReason"},
93 {4, nullptr, "GetSecurityParameter"},
94 {5, nullptr, "GetNetworkConfig"},
95 {100, nullptr, "AttachStateChangeEvent"},
96 {101, nullptr, "GetNetworkInfoLatestUpdate"},
97 {102, nullptr, "Scan"},
98 {103, nullptr, "ScanPrivate"},
99 {104, nullptr, "SetWirelessControllerRestriction"},
100 {200, nullptr, "OpenAccessPoint"},
101 {201, nullptr, "CloseAccessPoint"},
102 {202, nullptr, "CreateNetwork"},
103 {203, nullptr, "CreateNetworkPrivate"},
104 {204, nullptr, "DestroyNetwork"},
105 {205, nullptr, "Reject"},
106 {206, nullptr, "SetAdvertiseData"},
107 {207, nullptr, "SetStationAcceptPolicy"},
108 {208, nullptr, "AddAcceptFilterEntry"},
109 {209, nullptr, "ClearAcceptFilter"},
110 {300, nullptr, "OpenStation"},
111 {301, nullptr, "CloseStation"},
112 {302, nullptr, "Connect"},
113 {303, nullptr, "ConnectPrivate"},
114 {304, nullptr, "Disconnect"},
115 {400, nullptr, "InitializeSystem"},
116 {401, nullptr, "FinalizeSystem"},
117 {402, nullptr, "SetOperationMode"},
118 {403, &ISystemLocalCommunicationService::InitializeSystem2, "InitializeSystem2"},
119 }; 43 };
120 // clang-format on 44 // clang-format on
121 45
@@ -123,687 +47,78 @@ public:
123 } 47 }
124 48
125private: 49private:
126 void InitializeSystem2(HLERequestContext& ctx) { 50 Result CreateSystemLocalCommunicationService(
127 LOG_WARNING(Service_LDN, "(STUBBED) called"); 51 OutInterface<ISystemLocalCommunicationService> out_interface) {
128
129 IPC::ResponseBuilder rb{ctx, 2};
130 rb.Push(ResultSuccess);
131 }
132};
133
134class IUserLocalCommunicationService final
135 : public ServiceFramework<IUserLocalCommunicationService> {
136public:
137 explicit IUserLocalCommunicationService(Core::System& system_)
138 : ServiceFramework{system_, "IUserLocalCommunicationService"},
139 service_context{system, "IUserLocalCommunicationService"},
140 room_network{system_.GetRoomNetwork()}, lan_discovery{room_network} {
141 // clang-format off
142 static const FunctionInfo functions[] = {
143 {0, &IUserLocalCommunicationService::GetState, "GetState"},
144 {1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"},
145 {2, &IUserLocalCommunicationService::GetIpv4Address, "GetIpv4Address"},
146 {3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"},
147 {4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"},
148 {5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"},
149 {100, &IUserLocalCommunicationService::AttachStateChangeEvent, "AttachStateChangeEvent"},
150 {101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"},
151 {102, &IUserLocalCommunicationService::Scan, "Scan"},
152 {103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"},
153 {104, &IUserLocalCommunicationService::SetWirelessControllerRestriction, "SetWirelessControllerRestriction"},
154 {200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"},
155 {201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"},
156 {202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"},
157 {203, &IUserLocalCommunicationService::CreateNetworkPrivate, "CreateNetworkPrivate"},
158 {204, &IUserLocalCommunicationService::DestroyNetwork, "DestroyNetwork"},
159 {205, nullptr, "Reject"},
160 {206, &IUserLocalCommunicationService::SetAdvertiseData, "SetAdvertiseData"},
161 {207, &IUserLocalCommunicationService::SetStationAcceptPolicy, "SetStationAcceptPolicy"},
162 {208, &IUserLocalCommunicationService::AddAcceptFilterEntry, "AddAcceptFilterEntry"},
163 {209, nullptr, "ClearAcceptFilter"},
164 {300, &IUserLocalCommunicationService::OpenStation, "OpenStation"},
165 {301, &IUserLocalCommunicationService::CloseStation, "CloseStation"},
166 {302, &IUserLocalCommunicationService::Connect, "Connect"},
167 {303, nullptr, "ConnectPrivate"},
168 {304, &IUserLocalCommunicationService::Disconnect, "Disconnect"},
169 {400, &IUserLocalCommunicationService::Initialize, "Initialize"},
170 {401, &IUserLocalCommunicationService::Finalize, "Finalize"},
171 {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"},
172 };
173 // clang-format on
174
175 RegisterHandlers(functions);
176
177 state_change_event =
178 service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent");
179 }
180
181 ~IUserLocalCommunicationService() {
182 if (is_initialized) {
183 if (auto room_member = room_network.GetRoomMember().lock()) {
184 room_member->Unbind(ldn_packet_received);
185 }
186 }
187
188 service_context.CloseEvent(state_change_event);
189 }
190
191 /// Callback to parse and handle a received LDN packet.
192 void OnLDNPacketReceived(const Network::LDNPacket& packet) {
193 lan_discovery.ReceivePacket(packet);
194 }
195
196 void OnEventFired() {
197 state_change_event->Signal();
198 }
199
200 void GetState(HLERequestContext& ctx) {
201 State state = State::Error;
202
203 if (is_initialized) {
204 state = lan_discovery.GetState();
205 }
206
207 IPC::ResponseBuilder rb{ctx, 3};
208 rb.Push(ResultSuccess);
209 rb.PushEnum(state);
210 }
211
212 void GetNetworkInfo(HLERequestContext& ctx) {
213 const auto write_buffer_size = ctx.GetWriteBufferSize();
214
215 if (write_buffer_size != sizeof(NetworkInfo)) {
216 LOG_ERROR(Service_LDN, "Invalid buffer size {}", write_buffer_size);
217 IPC::ResponseBuilder rb{ctx, 2};
218 rb.Push(ResultBadInput);
219 return;
220 }
221
222 NetworkInfo network_info{};
223 const auto rc = lan_discovery.GetNetworkInfo(network_info);
224 if (rc.IsError()) {
225 LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
226 IPC::ResponseBuilder rb{ctx, 2};
227 rb.Push(rc);
228 return;
229 }
230
231 ctx.WriteBuffer<NetworkInfo>(network_info);
232 IPC::ResponseBuilder rb{ctx, 2};
233 rb.Push(ResultSuccess);
234 }
235
236 void GetIpv4Address(HLERequestContext& ctx) {
237 const auto network_interface = Network::GetSelectedNetworkInterface();
238
239 if (!network_interface) {
240 LOG_ERROR(Service_LDN, "No network interface available");
241 IPC::ResponseBuilder rb{ctx, 2};
242 rb.Push(ResultNoIpAddress);
243 return;
244 }
245
246 Ipv4Address current_address{Network::TranslateIPv4(network_interface->ip_address)};
247 Ipv4Address subnet_mask{Network::TranslateIPv4(network_interface->subnet_mask)};
248
249 // When we're connected to a room, spoof the hosts IP address
250 if (auto room_member = room_network.GetRoomMember().lock()) {
251 if (room_member->IsConnected()) {
252 current_address = room_member->GetFakeIpAddress();
253 }
254 }
255
256 std::reverse(std::begin(current_address), std::end(current_address)); // ntohl
257 std::reverse(std::begin(subnet_mask), std::end(subnet_mask)); // ntohl
258
259 IPC::ResponseBuilder rb{ctx, 4};
260 rb.Push(ResultSuccess);
261 rb.PushRaw(current_address);
262 rb.PushRaw(subnet_mask);
263 }
264
265 void GetDisconnectReason(HLERequestContext& ctx) {
266 IPC::ResponseBuilder rb{ctx, 3};
267 rb.Push(ResultSuccess);
268 rb.PushEnum(lan_discovery.GetDisconnectReason());
269 }
270
271 void GetSecurityParameter(HLERequestContext& ctx) {
272 SecurityParameter security_parameter{};
273 NetworkInfo info{};
274 const Result rc = lan_discovery.GetNetworkInfo(info);
275
276 if (rc.IsError()) {
277 LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
278 IPC::ResponseBuilder rb{ctx, 2};
279 rb.Push(rc);
280 return;
281 }
282
283 security_parameter.session_id = info.network_id.session_id;
284 std::memcpy(security_parameter.data.data(), info.ldn.security_parameter.data(),
285 sizeof(SecurityParameter::data));
286
287 IPC::ResponseBuilder rb{ctx, 10};
288 rb.Push(rc);
289 rb.PushRaw<SecurityParameter>(security_parameter);
290 }
291
292 void GetNetworkConfig(HLERequestContext& ctx) {
293 NetworkConfig config{};
294 NetworkInfo info{};
295 const Result rc = lan_discovery.GetNetworkInfo(info);
296
297 if (rc.IsError()) {
298 LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw);
299 IPC::ResponseBuilder rb{ctx, 2};
300 rb.Push(rc);
301 return;
302 }
303
304 config.intent_id = info.network_id.intent_id;
305 config.channel = info.common.channel;
306 config.node_count_max = info.ldn.node_count_max;
307 config.local_communication_version = info.ldn.nodes[0].local_communication_version;
308
309 IPC::ResponseBuilder rb{ctx, 10};
310 rb.Push(rc);
311 rb.PushRaw<NetworkConfig>(config);
312 }
313
314 void AttachStateChangeEvent(HLERequestContext& ctx) {
315 LOG_INFO(Service_LDN, "called");
316
317 IPC::ResponseBuilder rb{ctx, 2, 1};
318 rb.Push(ResultSuccess);
319 rb.PushCopyObjects(state_change_event->GetReadableEvent());
320 }
321
322 void GetNetworkInfoLatestUpdate(HLERequestContext& ctx) {
323 const std::size_t network_buffer_size = ctx.GetWriteBufferSize(0);
324 const std::size_t node_buffer_count = ctx.GetWriteBufferNumElements<NodeLatestUpdate>(1);
325
326 if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) {
327 LOG_ERROR(Service_LDN, "Invalid buffer, size = {}, count = {}", network_buffer_size,
328 node_buffer_count);
329 IPC::ResponseBuilder rb{ctx, 2};
330 rb.Push(ResultBadInput);
331 return;
332 }
333
334 NetworkInfo info{};
335 std::vector<NodeLatestUpdate> latest_update(node_buffer_count);
336
337 const auto rc = lan_discovery.GetNetworkInfo(info, latest_update, latest_update.size());
338 if (rc.IsError()) {
339 LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
340 IPC::ResponseBuilder rb{ctx, 2};
341 rb.Push(rc);
342 return;
343 }
344
345 ctx.WriteBuffer(info, 0);
346 ctx.WriteBuffer(latest_update, 1);
347
348 IPC::ResponseBuilder rb{ctx, 2};
349 rb.Push(ResultSuccess);
350 }
351
352 void Scan(HLERequestContext& ctx) {
353 ScanImpl(ctx);
354 }
355
356 void ScanPrivate(HLERequestContext& ctx) {
357 ScanImpl(ctx, true);
358 }
359
360 void ScanImpl(HLERequestContext& ctx, bool is_private = false) {
361 IPC::RequestParser rp{ctx};
362 const auto channel{rp.PopEnum<WifiChannel>()};
363 const auto scan_filter{rp.PopRaw<ScanFilter>()};
364
365 const std::size_t network_info_size = ctx.GetWriteBufferNumElements<NetworkInfo>();
366
367 if (network_info_size == 0) {
368 LOG_ERROR(Service_LDN, "Invalid buffer size {}", network_info_size);
369 IPC::ResponseBuilder rb{ctx, 2};
370 rb.Push(ResultBadInput);
371 return;
372 }
373
374 u16 count = 0;
375 std::vector<NetworkInfo> network_infos(network_info_size);
376 Result rc = lan_discovery.Scan(network_infos, count, scan_filter);
377
378 LOG_INFO(Service_LDN,
379 "called, channel={}, filter_scan_flag={}, filter_network_type={}, is_private={}",
380 channel, scan_filter.flag, scan_filter.network_type, is_private);
381
382 ctx.WriteBuffer(network_infos);
383
384 IPC::ResponseBuilder rb{ctx, 3};
385 rb.Push(rc);
386 rb.Push<u32>(count);
387 }
388
389 void SetWirelessControllerRestriction(HLERequestContext& ctx) {
390 LOG_WARNING(Service_LDN, "(STUBBED) called");
391
392 IPC::ResponseBuilder rb{ctx, 2};
393 rb.Push(ResultSuccess);
394 }
395
396 void OpenAccessPoint(HLERequestContext& ctx) {
397 LOG_INFO(Service_LDN, "called");
398
399 IPC::ResponseBuilder rb{ctx, 2};
400 rb.Push(lan_discovery.OpenAccessPoint());
401 }
402
403 void CloseAccessPoint(HLERequestContext& ctx) {
404 LOG_INFO(Service_LDN, "called");
405
406 IPC::ResponseBuilder rb{ctx, 2};
407 rb.Push(lan_discovery.CloseAccessPoint());
408 }
409
410 void CreateNetwork(HLERequestContext& ctx) {
411 LOG_INFO(Service_LDN, "called");
412
413 CreateNetworkImpl(ctx);
414 }
415
416 void CreateNetworkPrivate(HLERequestContext& ctx) {
417 LOG_INFO(Service_LDN, "called");
418
419 CreateNetworkImpl(ctx, true);
420 }
421
422 void CreateNetworkImpl(HLERequestContext& ctx, bool is_private = false) {
423 IPC::RequestParser rp{ctx};
424
425 const auto security_config{rp.PopRaw<SecurityConfig>()};
426 [[maybe_unused]] const auto security_parameter{is_private ? rp.PopRaw<SecurityParameter>()
427 : SecurityParameter{}};
428 const auto user_config{rp.PopRaw<UserConfig>()};
429 rp.Pop<u32>(); // Padding
430 const auto network_Config{rp.PopRaw<NetworkConfig>()};
431
432 IPC::ResponseBuilder rb{ctx, 2};
433 rb.Push(lan_discovery.CreateNetwork(security_config, user_config, network_Config));
434 }
435
436 void DestroyNetwork(HLERequestContext& ctx) {
437 LOG_INFO(Service_LDN, "called");
438
439 IPC::ResponseBuilder rb{ctx, 2};
440 rb.Push(lan_discovery.DestroyNetwork());
441 }
442
443 void SetAdvertiseData(HLERequestContext& ctx) {
444 const auto read_buffer = ctx.ReadBuffer();
445
446 IPC::ResponseBuilder rb{ctx, 2};
447 rb.Push(lan_discovery.SetAdvertiseData(read_buffer));
448 }
449
450 void SetStationAcceptPolicy(HLERequestContext& ctx) {
451 LOG_WARNING(Service_LDN, "(STUBBED) called");
452
453 IPC::ResponseBuilder rb{ctx, 2};
454 rb.Push(ResultSuccess);
455 }
456
457 void AddAcceptFilterEntry(HLERequestContext& ctx) {
458 LOG_WARNING(Service_LDN, "(STUBBED) called");
459
460 IPC::ResponseBuilder rb{ctx, 2};
461 rb.Push(ResultSuccess);
462 }
463
464 void OpenStation(HLERequestContext& ctx) {
465 LOG_INFO(Service_LDN, "called");
466
467 IPC::ResponseBuilder rb{ctx, 2};
468 rb.Push(lan_discovery.OpenStation());
469 }
470
471 void CloseStation(HLERequestContext& ctx) {
472 LOG_INFO(Service_LDN, "called");
473
474 IPC::ResponseBuilder rb{ctx, 2};
475 rb.Push(lan_discovery.CloseStation());
476 }
477
478 void Connect(HLERequestContext& ctx) {
479 IPC::RequestParser rp{ctx};
480 struct Parameters {
481 SecurityConfig security_config;
482 UserConfig user_config;
483 u32 local_communication_version;
484 u32 option;
485 };
486 static_assert(sizeof(Parameters) == 0x7C, "Parameters has incorrect size.");
487
488 const auto parameters{rp.PopRaw<Parameters>()};
489
490 LOG_INFO(Service_LDN,
491 "called, passphrase_size={}, security_mode={}, "
492 "local_communication_version={}",
493 parameters.security_config.passphrase_size,
494 parameters.security_config.security_mode, parameters.local_communication_version);
495
496 const auto read_buffer = ctx.ReadBuffer();
497 if (read_buffer.size() != sizeof(NetworkInfo)) {
498 LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!");
499 IPC::ResponseBuilder rb{ctx, 2};
500 rb.Push(ResultBadInput);
501 return;
502 }
503
504 NetworkInfo network_info{};
505 std::memcpy(&network_info, read_buffer.data(), read_buffer.size());
506
507 IPC::ResponseBuilder rb{ctx, 2};
508 rb.Push(lan_discovery.Connect(network_info, parameters.user_config,
509 static_cast<u16>(parameters.local_communication_version)));
510 }
511
512 void Disconnect(HLERequestContext& ctx) {
513 LOG_INFO(Service_LDN, "called");
514
515 IPC::ResponseBuilder rb{ctx, 2};
516 rb.Push(lan_discovery.Disconnect());
517 }
518
519 void Initialize(HLERequestContext& ctx) {
520 const auto rc = InitializeImpl(ctx);
521 if (rc.IsError()) {
522 LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw);
523 }
524
525 IPC::ResponseBuilder rb{ctx, 2};
526 rb.Push(rc);
527 }
528
529 void Finalize(HLERequestContext& ctx) {
530 if (auto room_member = room_network.GetRoomMember().lock()) {
531 room_member->Unbind(ldn_packet_received);
532 }
533
534 is_initialized = false;
535
536 IPC::ResponseBuilder rb{ctx, 2};
537 rb.Push(lan_discovery.Finalize());
538 }
539
540 void Initialize2(HLERequestContext& ctx) {
541 const auto rc = InitializeImpl(ctx);
542 if (rc.IsError()) {
543 LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw);
544 }
545
546 IPC::ResponseBuilder rb{ctx, 2};
547 rb.Push(rc);
548 }
549
550 Result InitializeImpl(HLERequestContext& ctx) {
551 const auto network_interface = Network::GetSelectedNetworkInterface();
552 if (!network_interface) {
553 LOG_ERROR(Service_LDN, "No network interface is set");
554 return ResultAirplaneModeEnabled;
555 }
556
557 if (auto room_member = room_network.GetRoomMember().lock()) {
558 ldn_packet_received = room_member->BindOnLdnPacketReceived(
559 [this](const Network::LDNPacket& packet) { OnLDNPacketReceived(packet); });
560 } else {
561 LOG_ERROR(Service_LDN, "Couldn't bind callback!");
562 return ResultAirplaneModeEnabled;
563 }
564
565 lan_discovery.Initialize([&]() { OnEventFired(); });
566 is_initialized = true;
567 return ResultSuccess;
568 }
569
570 KernelHelpers::ServiceContext service_context;
571 Kernel::KEvent* state_change_event;
572 Network::RoomNetwork& room_network;
573 LANDiscovery lan_discovery;
574
575 // Callback identifier for the OnLDNPacketReceived event.
576 Network::RoomMember::CallbackHandle<Network::LDNPacket> ldn_packet_received;
577
578 bool is_initialized{};
579};
580
581class LDNS final : public ServiceFramework<LDNS> {
582public:
583 explicit LDNS(Core::System& system_) : ServiceFramework{system_, "ldn:s"} {
584 // clang-format off
585 static const FunctionInfo functions[] = {
586 {0, &LDNS::CreateSystemLocalCommunicationService, "CreateSystemLocalCommunicationService"},
587 };
588 // clang-format on
589
590 RegisterHandlers(functions);
591 }
592
593 void CreateSystemLocalCommunicationService(HLERequestContext& ctx) {
594 LOG_DEBUG(Service_LDN, "called"); 52 LOG_DEBUG(Service_LDN, "called");
595 53
596 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 54 *out_interface = std::make_shared<ISystemLocalCommunicationService>(system);
597 rb.Push(ResultSuccess); 55 R_SUCCEED();
598 rb.PushIpcInterface<ISystemLocalCommunicationService>(system);
599 } 56 }
600}; 57};
601 58
602class LDNU final : public ServiceFramework<LDNU> { 59class IUserServiceCreator final : public ServiceFramework<IUserServiceCreator> {
603public: 60public:
604 explicit LDNU(Core::System& system_) : ServiceFramework{system_, "ldn:u"} { 61 explicit IUserServiceCreator(Core::System& system_) : ServiceFramework{system_, "ldn:u"} {
605 // clang-format off 62 // clang-format off
606 static const FunctionInfo functions[] = { 63 static const FunctionInfo functions[] = {
607 {0, &LDNU::CreateUserLocalCommunicationService, "CreateUserLocalCommunicationService"}, 64 {0, C<&IUserServiceCreator::CreateUserLocalCommunicationService>, "CreateUserLocalCommunicationService"},
608 }; 65 };
609 // clang-format on 66 // clang-format on
610 67
611 RegisterHandlers(functions); 68 RegisterHandlers(functions);
612 } 69 }
613 70
614 void CreateUserLocalCommunicationService(HLERequestContext& ctx) { 71private:
72 Result CreateUserLocalCommunicationService(
73 OutInterface<IUserLocalCommunicationService> out_interface) {
615 LOG_DEBUG(Service_LDN, "called"); 74 LOG_DEBUG(Service_LDN, "called");
616 75
617 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 76 *out_interface = std::make_shared<IUserLocalCommunicationService>(system);
618 rb.Push(ResultSuccess); 77 R_SUCCEED();
619 rb.PushIpcInterface<IUserLocalCommunicationService>(system);
620 } 78 }
621}; 79};
622 80
623class INetworkService final : public ServiceFramework<INetworkService> { 81class ISfServiceCreator final : public ServiceFramework<ISfServiceCreator> {
624public: 82public:
625 explicit INetworkService(Core::System& system_) : ServiceFramework{system_, "INetworkService"} { 83 explicit ISfServiceCreator(Core::System& system_, bool is_system_, const char* name_)
84 : ServiceFramework{system_, name_}, is_system{is_system_} {
626 // clang-format off 85 // clang-format off
627 static const FunctionInfo functions[] = { 86 static const FunctionInfo functions[] = {
628 {0, nullptr, "Initialize"}, 87 {0, C<&ISfServiceCreator::CreateNetworkService>, "CreateNetworkService"},
629 {256, nullptr, "AttachNetworkInterfaceStateChangeEvent"}, 88 {8, C<&ISfServiceCreator::CreateNetworkServiceMonitor>, "CreateNetworkServiceMonitor"},
630 {264, nullptr, "GetNetworkInterfaceLastError"},
631 {272, nullptr, "GetRole"},
632 {280, nullptr, "GetAdvertiseData"},
633 {288, nullptr, "GetGroupInfo"},
634 {296, nullptr, "GetGroupInfo2"},
635 {304, nullptr, "GetGroupOwner"},
636 {312, nullptr, "GetIpConfig"},
637 {320, nullptr, "GetLinkLevel"},
638 {512, nullptr, "Scan"},
639 {768, nullptr, "CreateGroup"},
640 {776, nullptr, "DestroyGroup"},
641 {784, nullptr, "SetAdvertiseData"},
642 {1536, nullptr, "SendToOtherGroup"},
643 {1544, nullptr, "RecvFromOtherGroup"},
644 {1552, nullptr, "AddAcceptableGroupId"},
645 {1560, nullptr, "ClearAcceptableGroupId"},
646 }; 89 };
647 // clang-format on 90 // clang-format on
648 91
649 RegisterHandlers(functions); 92 RegisterHandlers(functions);
650 } 93 }
651};
652
653class INetworkServiceMonitor final : public ServiceFramework<INetworkServiceMonitor> {
654public:
655 explicit INetworkServiceMonitor(Core::System& system_)
656 : ServiceFramework{system_, "INetworkServiceMonitor"} {
657 // clang-format off
658 static const FunctionInfo functions[] = {
659 {0, &INetworkServiceMonitor::Initialize, "Initialize"},
660 {256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
661 {264, nullptr, "GetNetworkInterfaceLastError"},
662 {272, nullptr, "GetRole"},
663 {280, nullptr, "GetAdvertiseData"},
664 {281, nullptr, "GetAdvertiseData2"},
665 {288, nullptr, "GetGroupInfo"},
666 {296, nullptr, "GetGroupInfo2"},
667 {304, nullptr, "GetGroupOwner"},
668 {312, nullptr, "GetIpConfig"},
669 {320, nullptr, "GetLinkLevel"},
670 {328, nullptr, "AttachJoinEvent"},
671 {336, nullptr, "GetMembers"},
672 };
673 // clang-format on
674
675 RegisterHandlers(functions);
676 }
677
678 void Initialize(HLERequestContext& ctx) {
679 LOG_WARNING(Service_LDN, "(STUBBED) called");
680
681 IPC::ResponseBuilder rb{ctx, 2};
682 rb.Push(ResultDisabled);
683 }
684};
685
686class LP2PAPP final : public ServiceFramework<LP2PAPP> {
687public:
688 explicit LP2PAPP(Core::System& system_) : ServiceFramework{system_, "lp2p:app"} {
689 // clang-format off
690 static const FunctionInfo functions[] = {
691 {0, &LP2PAPP::CreateMonitorService, "CreateNetworkService"},
692 {8, &LP2PAPP::CreateMonitorService, "CreateNetworkServiceMonitor"},
693 };
694 // clang-format on
695
696 RegisterHandlers(functions);
697 }
698
699 void CreateNetworkervice(HLERequestContext& ctx) {
700 IPC::RequestParser rp{ctx};
701 const u64 reserved_input = rp.Pop<u64>();
702 const u32 input = rp.Pop<u32>();
703
704 LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input,
705 input);
706
707 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
708 rb.Push(ResultSuccess);
709 rb.PushIpcInterface<INetworkService>(system);
710 }
711
712 void CreateMonitorService(HLERequestContext& ctx) {
713 IPC::RequestParser rp{ctx};
714 const u64 reserved_input = rp.Pop<u64>();
715
716 LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input);
717
718 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
719 rb.Push(ResultSuccess);
720 rb.PushIpcInterface<INetworkServiceMonitor>(system);
721 }
722};
723
724class LP2PSYS final : public ServiceFramework<LP2PSYS> {
725public:
726 explicit LP2PSYS(Core::System& system_) : ServiceFramework{system_, "lp2p:sys"} {
727 // clang-format off
728 static const FunctionInfo functions[] = {
729 {0, &LP2PSYS::CreateMonitorService, "CreateNetworkService"},
730 {8, &LP2PSYS::CreateMonitorService, "CreateNetworkServiceMonitor"},
731 };
732 // clang-format on
733
734 RegisterHandlers(functions);
735 }
736
737 void CreateNetworkervice(HLERequestContext& ctx) {
738 IPC::RequestParser rp{ctx};
739 const u64 reserved_input = rp.Pop<u64>();
740 const u32 input = rp.Pop<u32>();
741 94
95private:
96 Result CreateNetworkService(OutInterface<ISfService> out_interface, u32 input,
97 u64 reserved_input) {
742 LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input, 98 LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input,
743 input); 99 input);
744 100
745 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 101 *out_interface = std::make_shared<ISfService>(system);
746 rb.Push(ResultSuccess); 102 R_SUCCEED();
747 rb.PushIpcInterface<INetworkService>(system);
748 } 103 }
749 104
750 void CreateMonitorService(HLERequestContext& ctx) { 105 Result CreateNetworkServiceMonitor(OutInterface<ISfServiceMonitor> out_interface,
751 IPC::RequestParser rp{ctx}; 106 u64 reserved_input) {
752 const u64 reserved_input = rp.Pop<u64>();
753
754 LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input); 107 LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input);
755 108
756 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 109 *out_interface = std::make_shared<ISfServiceMonitor>(system);
757 rb.Push(ResultSuccess); 110 R_SUCCEED();
758 rb.PushIpcInterface<INetworkServiceMonitor>(system);
759 } 111 }
760};
761 112
762class ISfMonitorService final : public ServiceFramework<ISfMonitorService> { 113 bool is_system{};
763public:
764 explicit ISfMonitorService(Core::System& system_)
765 : ServiceFramework{system_, "ISfMonitorService"} {
766 // clang-format off
767 static const FunctionInfo functions[] = {
768 {0, &ISfMonitorService::Initialize, "Initialize"},
769 {288, &ISfMonitorService::GetGroupInfo, "GetGroupInfo"},
770 {320, nullptr, "GetLinkLevel"},
771 };
772 // clang-format on
773
774 RegisterHandlers(functions);
775 }
776
777private:
778 void Initialize(HLERequestContext& ctx) {
779 LOG_WARNING(Service_LDN, "(STUBBED) called");
780
781 IPC::ResponseBuilder rb{ctx, 3};
782 rb.Push(ResultSuccess);
783 rb.Push(0);
784 }
785
786 void GetGroupInfo(HLERequestContext& ctx) {
787 LOG_WARNING(Service_LDN, "(STUBBED) called");
788
789 struct GroupInfo {
790 std::array<u8, 0x200> info;
791 };
792
793 GroupInfo group_info{};
794
795 ctx.WriteBuffer(group_info);
796 IPC::ResponseBuilder rb{ctx, 2};
797 rb.Push(ResultSuccess);
798 }
799}; 114};
800 115
801class LP2PM final : public ServiceFramework<LP2PM> { 116class ISfMonitorServiceCreator final : public ServiceFramework<ISfMonitorServiceCreator> {
802public: 117public:
803 explicit LP2PM(Core::System& system_) : ServiceFramework{system_, "lp2p:m"} { 118 explicit ISfMonitorServiceCreator(Core::System& system_) : ServiceFramework{system_, "lp2p:m"} {
804 // clang-format off 119 // clang-format off
805 static const FunctionInfo functions[] = { 120 static const FunctionInfo functions[] = {
806 {0, &LP2PM::CreateMonitorService, "CreateMonitorService"}, 121 {0, C<&ISfMonitorServiceCreator::CreateMonitorService>, "CreateMonitorService"},
807 }; 122 };
808 // clang-format on 123 // clang-format on
809 124
@@ -811,28 +126,27 @@ public:
811 } 126 }
812 127
813private: 128private:
814 void CreateMonitorService(HLERequestContext& ctx) { 129 Result CreateMonitorService(OutInterface<ISfMonitorService> out_interface, u64 reserved_input) {
815 IPC::RequestParser rp{ctx};
816 const u64 reserved_input = rp.Pop<u64>();
817
818 LOG_INFO(Service_LDN, "called, reserved_input={}", reserved_input); 130 LOG_INFO(Service_LDN, "called, reserved_input={}", reserved_input);
819 131
820 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 132 *out_interface = std::make_shared<ISfMonitorService>(system);
821 rb.Push(ResultSuccess); 133 R_SUCCEED();
822 rb.PushIpcInterface<ISfMonitorService>(system);
823 } 134 }
824}; 135};
825 136
826void LoopProcess(Core::System& system) { 137void LoopProcess(Core::System& system) {
827 auto server_manager = std::make_unique<ServerManager>(system); 138 auto server_manager = std::make_unique<ServerManager>(system);
828 139
829 server_manager->RegisterNamedService("ldn:m", std::make_shared<LDNM>(system)); 140 server_manager->RegisterNamedService("ldn:m", std::make_shared<IMonitorServiceCreator>(system));
830 server_manager->RegisterNamedService("ldn:s", std::make_shared<LDNS>(system)); 141 server_manager->RegisterNamedService("ldn:s", std::make_shared<ISystemServiceCreator>(system));
831 server_manager->RegisterNamedService("ldn:u", std::make_shared<LDNU>(system)); 142 server_manager->RegisterNamedService("ldn:u", std::make_shared<IUserServiceCreator>(system));
832 143
833 server_manager->RegisterNamedService("lp2p:app", std::make_shared<LP2PAPP>(system)); 144 server_manager->RegisterNamedService(
834 server_manager->RegisterNamedService("lp2p:sys", std::make_shared<LP2PSYS>(system)); 145 "lp2p:app", std::make_shared<ISfServiceCreator>(system, false, "lp2p:app"));
835 server_manager->RegisterNamedService("lp2p:m", std::make_shared<LP2PM>(system)); 146 server_manager->RegisterNamedService(
147 "lp2p:sys", std::make_shared<ISfServiceCreator>(system, true, "lp2p:sys"));
148 server_manager->RegisterNamedService("lp2p:m",
149 std::make_shared<ISfMonitorServiceCreator>(system));
836 150
837 ServerManager::RunServer(std::move(server_manager)); 151 ServerManager::RunServer(std::move(server_manager));
838} 152}
diff --git a/src/core/hle/service/ldn/ldn.h b/src/core/hle/service/ldn/ldn.h
index f4a319168..dae037fa8 100644
--- a/src/core/hle/service/ldn/ldn.h
+++ b/src/core/hle/service/ldn/ldn.h
@@ -3,12 +3,6 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/kernel/k_event.h"
7#include "core/hle/result.h"
8#include "core/hle/service/ipc_helpers.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/sm/sm.h"
11
12namespace Core { 6namespace Core {
13class System; 7class System;
14} 8}
diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h
index 44c2c773b..6198aa07b 100644
--- a/src/core/hle/service/ldn/ldn_types.h
+++ b/src/core/hle/service/ldn/ldn_types.h
@@ -123,6 +123,18 @@ enum class NodeStatus : u8 {
123 Connected, 123 Connected,
124}; 124};
125 125
126enum class WirelessControllerRestriction : u32 {
127 None,
128 Default,
129};
130
131struct ConnectOption {
132 union {
133 u32 raw;
134 };
135};
136static_assert(sizeof(ConnectOption) == 0x4, "ConnectOption is an invalid size");
137
126struct NodeLatestUpdate { 138struct NodeLatestUpdate {
127 NodeStateChange state_change; 139 NodeStateChange state_change;
128 INSERT_PADDING_BYTES(0x7); // Unknown 140 INSERT_PADDING_BYTES(0x7); // Unknown
@@ -139,9 +151,9 @@ static_assert(sizeof(SessionId) == 0x10, "SessionId is an invalid size");
139 151
140struct IntentId { 152struct IntentId {
141 u64 local_communication_id; 153 u64 local_communication_id;
142 INSERT_PADDING_BYTES(0x2); // Reserved 154 INSERT_PADDING_BYTES_NOINIT(0x2); // Reserved
143 u16 scene_id; 155 u16 scene_id;
144 INSERT_PADDING_BYTES(0x4); // Reserved 156 INSERT_PADDING_BYTES_NOINIT(0x4); // Reserved
145}; 157};
146static_assert(sizeof(IntentId) == 0x10, "IntentId is an invalid size"); 158static_assert(sizeof(IntentId) == 0x10, "IntentId is an invalid size");
147 159
@@ -152,13 +164,14 @@ struct NetworkId {
152static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size"); 164static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size");
153 165
154struct Ssid { 166struct Ssid {
155 u8 length{}; 167 u8 length;
156 std::array<char, SsidLengthMax + 1> raw{}; 168 std::array<char, SsidLengthMax + 1> raw;
157 169
158 Ssid() = default; 170 Ssid() = default;
159 171
160 constexpr explicit Ssid(std::string_view data) { 172 constexpr explicit Ssid(std::string_view data) {
161 length = static_cast<u8>(std::min(data.size(), SsidLengthMax)); 173 length = static_cast<u8>(std::min(data.size(), SsidLengthMax));
174 raw = {};
162 data.copy(raw.data(), length); 175 data.copy(raw.data(), length);
163 raw[length] = 0; 176 raw[length] = 0;
164 } 177 }
@@ -181,7 +194,7 @@ using Ipv4Address = std::array<u8, 4>;
181static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size"); 194static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size");
182 195
183struct MacAddress { 196struct MacAddress {
184 std::array<u8, 6> raw{}; 197 std::array<u8, 6> raw;
185 198
186 friend bool operator==(const MacAddress& lhs, const MacAddress& rhs) = default; 199 friend bool operator==(const MacAddress& lhs, const MacAddress& rhs) = default;
187}; 200};
@@ -211,7 +224,7 @@ struct CommonNetworkInfo {
211 WifiChannel channel; 224 WifiChannel channel;
212 LinkLevel link_level; 225 LinkLevel link_level;
213 PackedNetworkType network_type; 226 PackedNetworkType network_type;
214 INSERT_PADDING_BYTES(0x4); 227 INSERT_PADDING_BYTES_NOINIT(0x4);
215}; 228};
216static_assert(sizeof(CommonNetworkInfo) == 0x30, "CommonNetworkInfo is an invalid size"); 229static_assert(sizeof(CommonNetworkInfo) == 0x30, "CommonNetworkInfo is an invalid size");
217 230
@@ -221,9 +234,9 @@ struct NodeInfo {
221 s8 node_id; 234 s8 node_id;
222 u8 is_connected; 235 u8 is_connected;
223 std::array<u8, UserNameBytesMax + 1> user_name; 236 std::array<u8, UserNameBytesMax + 1> user_name;
224 INSERT_PADDING_BYTES(0x1); // Reserved 237 INSERT_PADDING_BYTES_NOINIT(0x1); // Reserved
225 s16 local_communication_version; 238 s16 local_communication_version;
226 INSERT_PADDING_BYTES(0x10); // Reserved 239 INSERT_PADDING_BYTES_NOINIT(0x10); // Reserved
227}; 240};
228static_assert(sizeof(NodeInfo) == 0x40, "NodeInfo is an invalid size"); 241static_assert(sizeof(NodeInfo) == 0x40, "NodeInfo is an invalid size");
229 242
@@ -232,14 +245,14 @@ struct LdnNetworkInfo {
232 SecurityMode security_mode; 245 SecurityMode security_mode;
233 AcceptPolicy station_accept_policy; 246 AcceptPolicy station_accept_policy;
234 u8 has_action_frame; 247 u8 has_action_frame;
235 INSERT_PADDING_BYTES(0x2); // Padding 248 INSERT_PADDING_BYTES_NOINIT(0x2); // Padding
236 u8 node_count_max; 249 u8 node_count_max;
237 u8 node_count; 250 u8 node_count;
238 std::array<NodeInfo, NodeCountMax> nodes; 251 std::array<NodeInfo, NodeCountMax> nodes;
239 INSERT_PADDING_BYTES(0x2); // Reserved 252 INSERT_PADDING_BYTES_NOINIT(0x2); // Reserved
240 u16 advertise_data_size; 253 u16 advertise_data_size;
241 std::array<u8, AdvertiseDataSizeMax> advertise_data; 254 std::array<u8, AdvertiseDataSizeMax> advertise_data;
242 INSERT_PADDING_BYTES(0x8C); // Reserved 255 INSERT_PADDING_BYTES_NOINIT(0x8C); // Reserved
243 u64 random_authentication_id; 256 u64 random_authentication_id;
244}; 257};
245static_assert(sizeof(LdnNetworkInfo) == 0x430, "LdnNetworkInfo is an invalid size"); 258static_assert(sizeof(LdnNetworkInfo) == 0x430, "LdnNetworkInfo is an invalid size");
@@ -250,6 +263,7 @@ struct NetworkInfo {
250 LdnNetworkInfo ldn; 263 LdnNetworkInfo ldn;
251}; 264};
252static_assert(sizeof(NetworkInfo) == 0x480, "NetworkInfo is an invalid size"); 265static_assert(sizeof(NetworkInfo) == 0x480, "NetworkInfo is an invalid size");
266static_assert(std::is_trivial_v<NetworkInfo>, "NetworkInfo type must be trivially copyable.");
253 267
254struct SecurityConfig { 268struct SecurityConfig {
255 SecurityMode security_mode; 269 SecurityMode security_mode;
@@ -303,4 +317,36 @@ struct AddressList {
303}; 317};
304static_assert(sizeof(AddressList) == 0x60, "AddressList is an invalid size"); 318static_assert(sizeof(AddressList) == 0x60, "AddressList is an invalid size");
305 319
320struct GroupInfo {
321 std::array<u8, 0x200> info;
322};
323
324struct CreateNetworkConfig {
325 SecurityConfig security_config;
326 UserConfig user_config;
327 INSERT_PADDING_BYTES(0x4);
328 NetworkConfig network_config;
329};
330static_assert(sizeof(CreateNetworkConfig) == 0x98, "CreateNetworkConfig is an invalid size");
331
332#pragma pack(push, 4)
333struct CreateNetworkConfigPrivate {
334 SecurityConfig security_config;
335 SecurityParameter security_parameter;
336 UserConfig user_config;
337 INSERT_PADDING_BYTES(0x4);
338 NetworkConfig network_config;
339};
340#pragma pack(pop)
341static_assert(sizeof(CreateNetworkConfigPrivate) == 0xB8,
342 "CreateNetworkConfigPrivate is an invalid size");
343
344struct ConnectNetworkData {
345 SecurityConfig security_config;
346 UserConfig user_config;
347 s32 local_communication_version;
348 ConnectOption option;
349};
350static_assert(sizeof(ConnectNetworkData) == 0x7c, "ConnectNetworkData is an invalid size");
351
306} // namespace Service::LDN 352} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/monitor_service.cpp b/src/core/hle/service/ldn/monitor_service.cpp
new file mode 100644
index 000000000..3471f69da
--- /dev/null
+++ b/src/core/hle/service/ldn/monitor_service.cpp
@@ -0,0 +1,43 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/ldn/monitor_service.h"
6
7namespace Service::LDN {
8
9IMonitorService::IMonitorService(Core::System& system_)
10 : ServiceFramework{system_, "IMonitorService"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, C<&IMonitorService::GetStateForMonitor>, "GetStateForMonitor"},
14 {1, nullptr, "GetNetworkInfoForMonitor"},
15 {2, nullptr, "GetIpv4AddressForMonitor"},
16 {3, nullptr, "GetDisconnectReasonForMonitor"},
17 {4, nullptr, "GetSecurityParameterForMonitor"},
18 {5, nullptr, "GetNetworkConfigForMonitor"},
19 {100, C<&IMonitorService::InitializeMonitor>, "InitializeMonitor"},
20 {101, nullptr, "FinalizeMonitor"},
21 };
22 // clang-format on
23
24 RegisterHandlers(functions);
25}
26
27IMonitorService::~IMonitorService() = default;
28
29Result IMonitorService::GetStateForMonitor(Out<State> out_state) {
30 LOG_INFO(Service_LDN, "called");
31
32 *out_state = state;
33 R_SUCCEED();
34}
35
36Result IMonitorService::InitializeMonitor() {
37 LOG_INFO(Service_LDN, "called");
38
39 state = State::Initialized;
40 R_SUCCEED();
41}
42
43} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/monitor_service.h b/src/core/hle/service/ldn/monitor_service.h
new file mode 100644
index 000000000..61aacef30
--- /dev/null
+++ b/src/core/hle/service/ldn/monitor_service.h
@@ -0,0 +1,28 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/ldn/ldn_types.h"
8#include "core/hle/service/service.h"
9
10namespace Core {
11class System;
12}
13
14namespace Service::LDN {
15
16class IMonitorService final : public ServiceFramework<IMonitorService> {
17public:
18 explicit IMonitorService(Core::System& system_);
19 ~IMonitorService() override;
20
21private:
22 Result GetStateForMonitor(Out<State> out_state);
23 Result InitializeMonitor();
24
25 State state{State::None};
26};
27
28} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/sf_monitor_service.cpp b/src/core/hle/service/ldn/sf_monitor_service.cpp
new file mode 100644
index 000000000..9e6736ff2
--- /dev/null
+++ b/src/core/hle/service/ldn/sf_monitor_service.cpp
@@ -0,0 +1,40 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/ldn/ldn_types.h"
6#include "core/hle/service/ldn/sf_monitor_service.h"
7
8namespace Service::LDN {
9
10ISfMonitorService::ISfMonitorService(Core::System& system_)
11 : ServiceFramework{system_, "ISfMonitorService"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {0, C<&ISfMonitorService::Initialize>, "Initialize"},
15 {288, C<&ISfMonitorService::GetGroupInfo>, "GetGroupInfo"},
16 {320, nullptr, "GetLinkLevel"},
17 };
18 // clang-format on
19
20 RegisterHandlers(functions);
21}
22
23ISfMonitorService::~ISfMonitorService() = default;
24
25Result ISfMonitorService::Initialize(Out<u32> out_value) {
26 LOG_WARNING(Service_LDN, "(STUBBED) called");
27
28 *out_value = 0;
29 R_SUCCEED();
30}
31
32Result ISfMonitorService::GetGroupInfo(
33 OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info) {
34 LOG_WARNING(Service_LDN, "(STUBBED) called");
35
36 *out_group_info = GroupInfo{};
37 R_SUCCEED();
38}
39
40} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/sf_monitor_service.h b/src/core/hle/service/ldn/sf_monitor_service.h
new file mode 100644
index 000000000..d02115201
--- /dev/null
+++ b/src/core/hle/service/ldn/sf_monitor_service.h
@@ -0,0 +1,26 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::LDN {
14struct GroupInfo;
15
16class ISfMonitorService final : public ServiceFramework<ISfMonitorService> {
17public:
18 explicit ISfMonitorService(Core::System& system_);
19 ~ISfMonitorService() override;
20
21private:
22 Result Initialize(Out<u32> out_value);
23 Result GetGroupInfo(OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info);
24};
25
26} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/sf_service.cpp b/src/core/hle/service/ldn/sf_service.cpp
new file mode 100644
index 000000000..61cabe219
--- /dev/null
+++ b/src/core/hle/service/ldn/sf_service.cpp
@@ -0,0 +1,37 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/ldn/sf_service.h"
5
6namespace Service::LDN {
7
8ISfService::ISfService(Core::System& system_) : ServiceFramework{system_, "ISfService"} {
9 // clang-format off
10 static const FunctionInfo functions[] = {
11 {0, nullptr, "Initialize"},
12 {256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
13 {264, nullptr, "GetNetworkInterfaceLastError"},
14 {272, nullptr, "GetRole"},
15 {280, nullptr, "GetAdvertiseData"},
16 {288, nullptr, "GetGroupInfo"},
17 {296, nullptr, "GetGroupInfo2"},
18 {304, nullptr, "GetGroupOwner"},
19 {312, nullptr, "GetIpConfig"},
20 {320, nullptr, "GetLinkLevel"},
21 {512, nullptr, "Scan"},
22 {768, nullptr, "CreateGroup"},
23 {776, nullptr, "DestroyGroup"},
24 {784, nullptr, "SetAdvertiseData"},
25 {1536, nullptr, "SendToOtherGroup"},
26 {1544, nullptr, "RecvFromOtherGroup"},
27 {1552, nullptr, "AddAcceptableGroupId"},
28 {1560, nullptr, "ClearAcceptableGroupId"},
29 };
30 // clang-format on
31
32 RegisterHandlers(functions);
33}
34
35ISfService::~ISfService() = default;
36
37} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/sf_service.h b/src/core/hle/service/ldn/sf_service.h
new file mode 100644
index 000000000..05534b567
--- /dev/null
+++ b/src/core/hle/service/ldn/sf_service.h
@@ -0,0 +1,21 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::LDN {
14
15class ISfService final : public ServiceFramework<ISfService> {
16public:
17 explicit ISfService(Core::System& system_);
18 ~ISfService() override;
19};
20
21} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/sf_service_monitor.cpp b/src/core/hle/service/ldn/sf_service_monitor.cpp
new file mode 100644
index 000000000..33e3c1d69
--- /dev/null
+++ b/src/core/hle/service/ldn/sf_service_monitor.cpp
@@ -0,0 +1,50 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/ldn/ldn_types.h"
6#include "core/hle/service/ldn/sf_service_monitor.h"
7
8namespace Service::LDN {
9
10ISfServiceMonitor::ISfServiceMonitor(Core::System& system_)
11 : ServiceFramework{system_, "ISfServiceMonitor"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {0, C<&ISfServiceMonitor::Initialize>, "Initialize"},
15 {256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
16 {264, nullptr, "GetNetworkInterfaceLastError"},
17 {272, nullptr, "GetRole"},
18 {280, nullptr, "GetAdvertiseData"},
19 {281, nullptr, "GetAdvertiseData2"},
20 {288, C<&ISfServiceMonitor::GetGroupInfo>, "GetGroupInfo"},
21 {296, nullptr, "GetGroupInfo2"},
22 {304, nullptr, "GetGroupOwner"},
23 {312, nullptr, "GetIpConfig"},
24 {320, nullptr, "GetLinkLevel"},
25 {328, nullptr, "AttachJoinEvent"},
26 {336, nullptr, "GetMembers"},
27 };
28 // clang-format on
29
30 RegisterHandlers(functions);
31}
32
33ISfServiceMonitor::~ISfServiceMonitor() = default;
34
35Result ISfServiceMonitor::Initialize(Out<u32> out_value) {
36 LOG_WARNING(Service_LDN, "(STUBBED) called");
37
38 *out_value = 0;
39 R_SUCCEED();
40}
41
42Result ISfServiceMonitor::GetGroupInfo(
43 OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info) {
44 LOG_WARNING(Service_LDN, "(STUBBED) called");
45
46 *out_group_info = GroupInfo{};
47 R_SUCCEED();
48}
49
50} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/sf_service_monitor.h b/src/core/hle/service/ldn/sf_service_monitor.h
new file mode 100644
index 000000000..3cfc5005e
--- /dev/null
+++ b/src/core/hle/service/ldn/sf_service_monitor.h
@@ -0,0 +1,26 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::LDN {
14struct GroupInfo;
15
16class ISfServiceMonitor final : public ServiceFramework<ISfServiceMonitor> {
17public:
18 explicit ISfServiceMonitor(Core::System& system_);
19 ~ISfServiceMonitor() override;
20
21private:
22 Result Initialize(Out<u32> out_value);
23 Result GetGroupInfo(OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info);
24};
25
26} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/system_local_communication_service.cpp b/src/core/hle/service/ldn/system_local_communication_service.cpp
new file mode 100644
index 000000000..7b52223cd
--- /dev/null
+++ b/src/core/hle/service/ldn/system_local_communication_service.cpp
@@ -0,0 +1,56 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "core/hle/service/cmif_serialization.h"
5#include "core/hle/service/ldn/system_local_communication_service.h"
6
7namespace Service::LDN {
8
9ISystemLocalCommunicationService::ISystemLocalCommunicationService(Core::System& system_)
10 : ServiceFramework{system_, "ISystemLocalCommunicationService"} {
11 // clang-format off
12 static const FunctionInfo functions[] = {
13 {0, nullptr, "GetState"},
14 {1, nullptr, "GetNetworkInfo"},
15 {2, nullptr, "GetIpv4Address"},
16 {3, nullptr, "GetDisconnectReason"},
17 {4, nullptr, "GetSecurityParameter"},
18 {5, nullptr, "GetNetworkConfig"},
19 {100, nullptr, "AttachStateChangeEvent"},
20 {101, nullptr, "GetNetworkInfoLatestUpdate"},
21 {102, nullptr, "Scan"},
22 {103, nullptr, "ScanPrivate"},
23 {104, nullptr, "SetWirelessControllerRestriction"},
24 {200, nullptr, "OpenAccessPoint"},
25 {201, nullptr, "CloseAccessPoint"},
26 {202, nullptr, "CreateNetwork"},
27 {203, nullptr, "CreateNetworkPrivate"},
28 {204, nullptr, "DestroyNetwork"},
29 {205, nullptr, "Reject"},
30 {206, nullptr, "SetAdvertiseData"},
31 {207, nullptr, "SetStationAcceptPolicy"},
32 {208, nullptr, "AddAcceptFilterEntry"},
33 {209, nullptr, "ClearAcceptFilter"},
34 {300, nullptr, "OpenStation"},
35 {301, nullptr, "CloseStation"},
36 {302, nullptr, "Connect"},
37 {303, nullptr, "ConnectPrivate"},
38 {304, nullptr, "Disconnect"},
39 {400, nullptr, "InitializeSystem"},
40 {401, nullptr, "FinalizeSystem"},
41 {402, nullptr, "SetOperationMode"},
42 {403, C<&ISystemLocalCommunicationService::InitializeSystem2>, "InitializeSystem2"},
43 };
44 // clang-format on
45
46 RegisterHandlers(functions);
47}
48
49ISystemLocalCommunicationService::~ISystemLocalCommunicationService() = default;
50
51Result ISystemLocalCommunicationService::InitializeSystem2() {
52 LOG_WARNING(Service_LDN, "(STUBBED) called");
53 R_SUCCEED();
54}
55
56} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/system_local_communication_service.h b/src/core/hle/service/ldn/system_local_communication_service.h
new file mode 100644
index 000000000..a02b097ea
--- /dev/null
+++ b/src/core/hle/service/ldn/system_local_communication_service.h
@@ -0,0 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/service.h"
8
9namespace Core {
10class System;
11}
12
13namespace Service::LDN {
14
15class ISystemLocalCommunicationService final
16 : public ServiceFramework<ISystemLocalCommunicationService> {
17public:
18 explicit ISystemLocalCommunicationService(Core::System& system_);
19 ~ISystemLocalCommunicationService() override;
20
21private:
22 Result InitializeSystem2();
23};
24
25} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/user_local_communication_service.cpp b/src/core/hle/service/ldn/user_local_communication_service.cpp
new file mode 100644
index 000000000..f28368962
--- /dev/null
+++ b/src/core/hle/service/ldn/user_local_communication_service.cpp
@@ -0,0 +1,320 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include <memory>
5
6#include "core/core.h"
7#include "core/hle/kernel/k_event.h"
8#include "core/hle/service/cmif_serialization.h"
9#include "core/hle/service/ldn/ldn_results.h"
10#include "core/hle/service/ldn/ldn_types.h"
11#include "core/hle/service/ldn/user_local_communication_service.h"
12#include "core/hle/service/server_manager.h"
13#include "core/internal_network/network.h"
14#include "core/internal_network/network_interface.h"
15#include "network/network.h"
16
17// This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent
18#undef CreateEvent
19
20namespace Service::LDN {
21
22IUserLocalCommunicationService::IUserLocalCommunicationService(Core::System& system_)
23 : ServiceFramework{system_, "IUserLocalCommunicationService"},
24 service_context{system, "IUserLocalCommunicationService"},
25 room_network{system_.GetRoomNetwork()}, lan_discovery{room_network} {
26 // clang-format off
27 static const FunctionInfo functions[] = {
28 {0, C<&IUserLocalCommunicationService::GetState>, "GetState"},
29 {1, C<&IUserLocalCommunicationService::GetNetworkInfo>, "GetNetworkInfo"},
30 {2, C<&IUserLocalCommunicationService::GetIpv4Address>, "GetIpv4Address"},
31 {3, C<&IUserLocalCommunicationService::GetDisconnectReason>, "GetDisconnectReason"},
32 {4, C<&IUserLocalCommunicationService::GetSecurityParameter>, "GetSecurityParameter"},
33 {5, C<&IUserLocalCommunicationService::GetNetworkConfig>, "GetNetworkConfig"},
34 {100, C<&IUserLocalCommunicationService::AttachStateChangeEvent>, "AttachStateChangeEvent"},
35 {101, C<&IUserLocalCommunicationService::GetNetworkInfoLatestUpdate>, "GetNetworkInfoLatestUpdate"},
36 {102, C<&IUserLocalCommunicationService::Scan>, "Scan"},
37 {103, C<&IUserLocalCommunicationService::ScanPrivate>, "ScanPrivate"},
38 {104, C<&IUserLocalCommunicationService::SetWirelessControllerRestriction>, "SetWirelessControllerRestriction"},
39 {200, C<&IUserLocalCommunicationService::OpenAccessPoint>, "OpenAccessPoint"},
40 {201, C<&IUserLocalCommunicationService::CloseAccessPoint>, "CloseAccessPoint"},
41 {202, C<&IUserLocalCommunicationService::CreateNetwork>, "CreateNetwork"},
42 {203, C<&IUserLocalCommunicationService::CreateNetworkPrivate>, "CreateNetworkPrivate"},
43 {204, C<&IUserLocalCommunicationService::DestroyNetwork>, "DestroyNetwork"},
44 {205, nullptr, "Reject"},
45 {206, C<&IUserLocalCommunicationService::SetAdvertiseData>, "SetAdvertiseData"},
46 {207, C<&IUserLocalCommunicationService::SetStationAcceptPolicy>, "SetStationAcceptPolicy"},
47 {208, C<&IUserLocalCommunicationService::AddAcceptFilterEntry>, "AddAcceptFilterEntry"},
48 {209, nullptr, "ClearAcceptFilter"},
49 {300, C<&IUserLocalCommunicationService::OpenStation>, "OpenStation"},
50 {301, C<&IUserLocalCommunicationService::CloseStation>, "CloseStation"},
51 {302, C<&IUserLocalCommunicationService::Connect>, "Connect"},
52 {303, nullptr, "ConnectPrivate"},
53 {304, C<&IUserLocalCommunicationService::Disconnect>, "Disconnect"},
54 {400, C<&IUserLocalCommunicationService::Initialize>, "Initialize"},
55 {401, C<&IUserLocalCommunicationService::Finalize>, "Finalize"},
56 {402, C<&IUserLocalCommunicationService::Initialize2>, "Initialize2"},
57 };
58 // clang-format on
59
60 RegisterHandlers(functions);
61
62 state_change_event =
63 service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent");
64}
65
66IUserLocalCommunicationService::~IUserLocalCommunicationService() {
67 if (is_initialized) {
68 if (auto room_member = room_network.GetRoomMember().lock()) {
69 room_member->Unbind(ldn_packet_received);
70 }
71 }
72
73 service_context.CloseEvent(state_change_event);
74}
75
76Result IUserLocalCommunicationService::GetState(Out<State> out_state) {
77 *out_state = State::Error;
78
79 if (is_initialized) {
80 *out_state = lan_discovery.GetState();
81 }
82
83 LOG_INFO(Service_LDN, "called, state={}", *out_state);
84
85 R_SUCCEED();
86}
87
88Result IUserLocalCommunicationService::GetNetworkInfo(
89 OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info) {
90 LOG_INFO(Service_LDN, "called");
91
92 R_RETURN(lan_discovery.GetNetworkInfo(*out_network_info));
93}
94
95Result IUserLocalCommunicationService::GetIpv4Address(Out<Ipv4Address> out_current_address,
96 Out<Ipv4Address> out_subnet_mask) {
97 LOG_INFO(Service_LDN, "called");
98 const auto network_interface = Network::GetSelectedNetworkInterface();
99
100 R_UNLESS(network_interface.has_value(), ResultNoIpAddress);
101
102 *out_current_address = {Network::TranslateIPv4(network_interface->ip_address)};
103 *out_subnet_mask = {Network::TranslateIPv4(network_interface->subnet_mask)};
104
105 // When we're connected to a room, spoof the hosts IP address
106 if (auto room_member = room_network.GetRoomMember().lock()) {
107 if (room_member->IsConnected()) {
108 *out_current_address = room_member->GetFakeIpAddress();
109 }
110 }
111
112 std::reverse(std::begin(*out_current_address), std::end(*out_current_address)); // ntohl
113 std::reverse(std::begin(*out_subnet_mask), std::end(*out_subnet_mask)); // ntohl
114 R_SUCCEED();
115}
116
117Result IUserLocalCommunicationService::GetDisconnectReason(
118 Out<DisconnectReason> out_disconnect_reason) {
119 LOG_INFO(Service_LDN, "called");
120
121 *out_disconnect_reason = lan_discovery.GetDisconnectReason();
122 R_SUCCEED();
123}
124
125Result IUserLocalCommunicationService::GetSecurityParameter(
126 Out<SecurityParameter> out_security_parameter) {
127 LOG_INFO(Service_LDN, "called");
128
129 NetworkInfo info{};
130 R_TRY(lan_discovery.GetNetworkInfo(info));
131
132 out_security_parameter->session_id = info.network_id.session_id;
133 std::memcpy(out_security_parameter->data.data(), info.ldn.security_parameter.data(),
134 sizeof(SecurityParameter::data));
135 R_SUCCEED();
136}
137
138Result IUserLocalCommunicationService::GetNetworkConfig(Out<NetworkConfig> out_network_config) {
139 LOG_INFO(Service_LDN, "called");
140
141 NetworkInfo info{};
142 R_TRY(lan_discovery.GetNetworkInfo(info));
143
144 out_network_config->intent_id = info.network_id.intent_id;
145 out_network_config->channel = info.common.channel;
146 out_network_config->node_count_max = info.ldn.node_count_max;
147 out_network_config->local_communication_version = info.ldn.nodes[0].local_communication_version;
148 R_SUCCEED();
149}
150
151Result IUserLocalCommunicationService::AttachStateChangeEvent(
152 OutCopyHandle<Kernel::KReadableEvent> out_event) {
153 LOG_INFO(Service_LDN, "called");
154
155 *out_event = &state_change_event->GetReadableEvent();
156 R_SUCCEED();
157}
158
159Result IUserLocalCommunicationService::GetNetworkInfoLatestUpdate(
160 OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info,
161 OutArray<NodeLatestUpdate, BufferAttr_HipcPointer> out_node_latest_update) {
162 LOG_INFO(Service_LDN, "called");
163
164 R_UNLESS(!out_node_latest_update.empty(), ResultBadInput);
165
166 R_RETURN(lan_discovery.GetNetworkInfo(*out_network_info, out_node_latest_update));
167}
168
169Result IUserLocalCommunicationService::Scan(
170 Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
171 OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info) {
172 LOG_INFO(Service_LDN, "called, channel={}, filter_scan_flag={}, filter_network_type={}",
173 channel, scan_filter.flag, scan_filter.network_type);
174
175 R_UNLESS(!out_network_info.empty(), ResultBadInput);
176 R_RETURN(lan_discovery.Scan(out_network_info, *network_count, scan_filter));
177}
178
179Result IUserLocalCommunicationService::ScanPrivate(
180 Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
181 OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info) {
182 LOG_INFO(Service_LDN, "called, channel={}, filter_scan_flag={}, filter_network_type={}",
183 channel, scan_filter.flag, scan_filter.network_type);
184
185 R_UNLESS(out_network_info.empty(), ResultBadInput);
186 R_RETURN(lan_discovery.Scan(out_network_info, *network_count, scan_filter));
187}
188
189Result IUserLocalCommunicationService::SetWirelessControllerRestriction(
190 WirelessControllerRestriction wireless_restriction) {
191 LOG_WARNING(Service_LDN, "(STUBBED) called");
192 R_SUCCEED();
193}
194
195Result IUserLocalCommunicationService::OpenAccessPoint() {
196 LOG_INFO(Service_LDN, "called");
197
198 R_RETURN(lan_discovery.OpenAccessPoint());
199}
200
201Result IUserLocalCommunicationService::CloseAccessPoint() {
202 LOG_INFO(Service_LDN, "called");
203
204 R_RETURN(lan_discovery.CloseAccessPoint());
205}
206
207Result IUserLocalCommunicationService::CreateNetwork(const CreateNetworkConfig& create_config) {
208 LOG_INFO(Service_LDN, "called");
209
210 R_RETURN(lan_discovery.CreateNetwork(create_config.security_config, create_config.user_config,
211 create_config.network_config));
212}
213
214Result IUserLocalCommunicationService::CreateNetworkPrivate(
215 const CreateNetworkConfigPrivate& create_config,
216 InArray<AddressEntry, BufferAttr_HipcPointer> address_list) {
217 LOG_INFO(Service_LDN, "called");
218
219 R_RETURN(lan_discovery.CreateNetwork(create_config.security_config, create_config.user_config,
220 create_config.network_config));
221}
222
223Result IUserLocalCommunicationService::DestroyNetwork() {
224 LOG_INFO(Service_LDN, "called");
225
226 R_RETURN(lan_discovery.DestroyNetwork());
227}
228
229Result IUserLocalCommunicationService::SetAdvertiseData(
230 InBuffer<BufferAttr_HipcAutoSelect> buffer_data) {
231 LOG_INFO(Service_LDN, "called");
232
233 R_RETURN(lan_discovery.SetAdvertiseData(buffer_data));
234}
235
236Result IUserLocalCommunicationService::SetStationAcceptPolicy(AcceptPolicy accept_policy) {
237 LOG_WARNING(Service_LDN, "(STUBBED) called");
238 R_SUCCEED();
239}
240
241Result IUserLocalCommunicationService::AddAcceptFilterEntry(MacAddress mac_address) {
242 LOG_WARNING(Service_LDN, "(STUBBED) called");
243 R_SUCCEED();
244}
245
246Result IUserLocalCommunicationService::OpenStation() {
247 LOG_INFO(Service_LDN, "called");
248
249 R_RETURN(lan_discovery.OpenStation());
250}
251
252Result IUserLocalCommunicationService::CloseStation() {
253 LOG_INFO(Service_LDN, "called");
254
255 R_RETURN(lan_discovery.CloseStation());
256}
257
258Result IUserLocalCommunicationService::Connect(
259 const ConnectNetworkData& connect_data,
260 InLargeData<NetworkInfo, BufferAttr_HipcPointer> network_info) {
261 LOG_INFO(Service_LDN,
262 "called, passphrase_size={}, security_mode={}, "
263 "local_communication_version={}",
264 connect_data.security_config.passphrase_size,
265 connect_data.security_config.security_mode, connect_data.local_communication_version);
266
267 R_RETURN(lan_discovery.Connect(*network_info, connect_data.user_config,
268 static_cast<u16>(connect_data.local_communication_version)));
269}
270
271Result IUserLocalCommunicationService::Disconnect() {
272 LOG_INFO(Service_LDN, "called");
273
274 R_RETURN(lan_discovery.Disconnect());
275}
276
277Result IUserLocalCommunicationService::Initialize(ClientProcessId aruid) {
278 LOG_INFO(Service_LDN, "called, process_id={}", aruid.pid);
279
280 const auto network_interface = Network::GetSelectedNetworkInterface();
281 R_UNLESS(network_interface, ResultAirplaneModeEnabled);
282
283 if (auto room_member = room_network.GetRoomMember().lock()) {
284 ldn_packet_received = room_member->BindOnLdnPacketReceived(
285 [this](const Network::LDNPacket& packet) { OnLDNPacketReceived(packet); });
286 } else {
287 LOG_ERROR(Service_LDN, "Couldn't bind callback!");
288 R_RETURN(ResultAirplaneModeEnabled);
289 }
290
291 lan_discovery.Initialize([&]() { OnEventFired(); });
292 is_initialized = true;
293 R_SUCCEED();
294}
295
296Result IUserLocalCommunicationService::Finalize() {
297 LOG_INFO(Service_LDN, "called");
298 if (auto room_member = room_network.GetRoomMember().lock()) {
299 room_member->Unbind(ldn_packet_received);
300 }
301
302 is_initialized = false;
303
304 R_RETURN(lan_discovery.Finalize());
305}
306
307Result IUserLocalCommunicationService::Initialize2(u32 version, ClientProcessId process_id) {
308 LOG_INFO(Service_LDN, "called, version={}, process_id={}", version, process_id.pid);
309 R_RETURN(Initialize(process_id));
310}
311
312void IUserLocalCommunicationService::OnLDNPacketReceived(const Network::LDNPacket& packet) {
313 lan_discovery.ReceivePacket(packet);
314}
315
316void IUserLocalCommunicationService::OnEventFired() {
317 state_change_event->Signal();
318}
319
320} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/user_local_communication_service.h b/src/core/hle/service/ldn/user_local_communication_service.h
new file mode 100644
index 000000000..6698d10d2
--- /dev/null
+++ b/src/core/hle/service/ldn/user_local_communication_service.h
@@ -0,0 +1,103 @@
1// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/service/cmif_types.h"
7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/ldn/lan_discovery.h"
9#include "core/hle/service/ldn/ldn_types.h"
10#include "core/hle/service/service.h"
11
12namespace Core {
13class System;
14}
15
16namespace Network {
17class RoomNetwork;
18}
19
20namespace Service::LDN {
21
22class IUserLocalCommunicationService final
23 : public ServiceFramework<IUserLocalCommunicationService> {
24public:
25 explicit IUserLocalCommunicationService(Core::System& system_);
26 ~IUserLocalCommunicationService() override;
27
28private:
29 Result GetState(Out<State> out_state);
30
31 Result GetNetworkInfo(OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info);
32
33 Result GetIpv4Address(Out<Ipv4Address> out_current_address, Out<Ipv4Address> out_subnet_mask);
34
35 Result GetDisconnectReason(Out<DisconnectReason> out_disconnect_reason);
36
37 Result GetSecurityParameter(Out<SecurityParameter> out_security_parameter);
38
39 Result GetNetworkConfig(Out<NetworkConfig> out_network_config);
40
41 Result AttachStateChangeEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
42
43 Result GetNetworkInfoLatestUpdate(
44 OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info,
45 OutArray<NodeLatestUpdate, BufferAttr_HipcPointer> out_node_latest_update);
46
47 Result Scan(Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
48 OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info);
49
50 Result ScanPrivate(Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
51 OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info);
52
53 Result SetWirelessControllerRestriction(WirelessControllerRestriction wireless_restriction);
54
55 Result OpenAccessPoint();
56
57 Result CloseAccessPoint();
58
59 Result CreateNetwork(const CreateNetworkConfig& create_network_Config);
60
61 Result CreateNetworkPrivate(const CreateNetworkConfigPrivate& create_network_Config,
62 InArray<AddressEntry, BufferAttr_HipcPointer> address_list);
63
64 Result DestroyNetwork();
65
66 Result SetAdvertiseData(InBuffer<BufferAttr_HipcAutoSelect> buffer_data);
67
68 Result SetStationAcceptPolicy(AcceptPolicy accept_policy);
69
70 Result AddAcceptFilterEntry(MacAddress mac_address);
71
72 Result OpenStation();
73
74 Result CloseStation();
75
76 Result Connect(const ConnectNetworkData& connect_data,
77 InLargeData<NetworkInfo, BufferAttr_HipcPointer> network_info);
78
79 Result Disconnect();
80
81 Result Initialize(ClientProcessId aruid);
82
83 Result Finalize();
84
85 Result Initialize2(u32 version, ClientProcessId aruid);
86
87private:
88 /// Callback to parse and handle a received LDN packet.
89 void OnLDNPacketReceived(const Network::LDNPacket& packet);
90 void OnEventFired();
91
92 KernelHelpers::ServiceContext service_context;
93 Kernel::KEvent* state_change_event;
94 Network::RoomNetwork& room_network;
95 LANDiscovery lan_discovery;
96
97 // Callback identifier for the OnLDNPacketReceived event.
98 Network::RoomMember::CallbackHandle<Network::LDNPacket> ldn_packet_received;
99
100 bool is_initialized{};
101};
102
103} // namespace Service::LDN