diff --git a/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.cpp b/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.cpp index 4b118c69..2770460a 100644 --- a/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.cpp +++ b/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.cpp @@ -2,6 +2,7 @@ // Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/) #include "IUserLocalCommunicationService.h" +#include namespace skyline::service::ldn { IUserLocalCommunicationService::IUserLocalCommunicationService(const DeviceState &state, ServiceManager &manager) @@ -9,8 +10,39 @@ namespace skyline::service::ldn { event{std::make_shared(state, false)} {} Result IUserLocalCommunicationService::GetState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - static constexpr u32 StateNone{0x0}; - response.Push(StateNone); + response.Push(State::Error); + return {}; + } + + Result IUserLocalCommunicationService::GetNetworkInfo(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + if (request.outputBuf.at(0).size() != sizeof(NetworkInfo)) { + Logger::Error("Invalid input"); + return result::InvalidInput; + } + + NetworkInfo networkInfo{}; + request.outputBuf.at(0).as() = networkInfo; + return {}; + } + + Result IUserLocalCommunicationService::GetIpv4Address(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + + Result IUserLocalCommunicationService::GetDisconnectReason(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + response.Push(DisconnectReason::None); + return {}; + } + + Result IUserLocalCommunicationService::GetSecurityParameter(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + SecurityParameter securityParameter{}; + response.Push(securityParameter); + return {}; + } + + Result IUserLocalCommunicationService::GetNetworkConfig(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + NetworkConfig networkConfig{}; + response.Push(networkConfig); return {}; } @@ -21,15 +53,71 @@ namespace skyline::service::ldn { return {}; } + Result IUserLocalCommunicationService::GetNetworkInfoLatestUpdate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + const size_t networkBuffferSize{request.outputBuf.at(0).size()}; + const size_t nodeBufferCount{request.outputBuf.at(1).size() / sizeof(NodeLatestUpdate)}; + + if (nodeBufferCount == 0 || networkBuffferSize != sizeof(NetworkInfo)) + return result::InvalidInput; + + NetworkInfo networkInfo{}; + std::vector latestUpdate(nodeBufferCount); + + request.outputBuf.at(0).as() = networkInfo; + request.outputBuf.at(1).copy_from(latestUpdate); + return {}; + } + + Result IUserLocalCommunicationService::Scan(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + const size_t networkInfoSize{request.outputBuf.at(0).size() / sizeof(NetworkInfo)}; + + if (networkInfoSize == 0) + return result::InvalidInput; + + std::vector networkInfos(networkInfoSize); + request.outputBuf.at(0).copy_from(networkInfos); + response.Push(0); + return {}; + } + + Result IUserLocalCommunicationService::OpenAccessPoint(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + + Result IUserLocalCommunicationService::CreateNetwork(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + + Result IUserLocalCommunicationService::CreateNetworkPrivate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + + Result IUserLocalCommunicationService::SetAdvertiseData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + + Result IUserLocalCommunicationService::OpenStation(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + return {}; + } + Result IUserLocalCommunicationService::InitializeSystem(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return result::DeviceDisabled; + if (!*state.settings->isInternetEnabled) + return result::AirplaneModeEnabled; + + isInitialized = true; + return result::AirplaneModeEnabled; } Result IUserLocalCommunicationService::FinalizeSystem(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { + isInitialized = false; return {}; } Result IUserLocalCommunicationService::InitializeSystem2(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - return result::DeviceDisabled; + if (!*state.settings->isInternetEnabled) + return result::AirplaneModeEnabled; + + isInitialized = true; + return result::AirplaneModeEnabled; } } diff --git a/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.h b/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.h index fcedb2fe..4a54f78a 100644 --- a/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.h +++ b/app/src/main/cpp/skyline/services/ldn/IUserLocalCommunicationService.h @@ -7,9 +7,194 @@ namespace skyline::service::ldn { namespace result { - static constexpr Result DeviceDisabled{203, 22}; + constexpr Result AirplaneModeEnabled{203, 23}; + constexpr Result InvalidInput{203, 96}; } + constexpr size_t SsidLengthMax = 32; + constexpr size_t UserNameBytesMax = 32; + constexpr i32 NodeCountMax = 8; + constexpr size_t AdvertiseDataSizeMax = 384; + constexpr size_t PassphraseLengthMax = 64; + + enum class State : u32 { + None, + Initialized, + AccessPointOpened, + AccessPointCreated, + StationOpened, + StationConnected, + Error, + }; + + enum class DisconnectReason : i16 { + Unknown = -1, + None, + User, + System, + DestroyedByUser, + DestroyedBySystemRequest, + Admin, + SignalLost, + }; + + enum class WifiChannel : i16 { + 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 : i8 { + Bad, + Low, + Good, + Excellent, + }; + + enum class PackedNetworkType : u8 { + None, + General, + Ldn, + All, + }; + + enum class SecurityMode : u16 { + All, + Retail, + Debug, + }; + + enum class AcceptPolicy : u8 { + AcceptAll, + RejectAll, + BlackList, + WhiteList, + }; + + enum class NodeStateChange : u8 { + None, + Connect, + Disconnect, + DisconnectAndConnect, + }; + + struct IntentId { + u64 localCommunicationId; + u8 _pad0_[0x2]; + u16 sceneId; + u8 _pad1_[0x4]; + }; + static_assert(sizeof(IntentId) == 0x10); + + struct SessionId { + u64 high; + u64 low; + }; + static_assert(sizeof(SessionId) == 0x10); + + struct NetworkId { + IntentId intentId; + SessionId sessionId; + }; + static_assert(sizeof(NetworkId) == 0x20); + + struct MacAddress { + std::array raw{}; + }; + static_assert(sizeof(MacAddress) == 0x6); + + struct Ssid { + u8 length{}; + std::array raw{}; + }; + static_assert(sizeof(Ssid) == 0x22); + + struct CommonNetworkInfo { + MacAddress bssid; + Ssid ssid; + WifiChannel channel; + LinkLevel linkLevel; + PackedNetworkType networkType; + u8 _pad0_[0x4]; + }; + static_assert(sizeof(CommonNetworkInfo) == 0x30); + + struct NodeInfo { + std::array ipv4Address; + MacAddress macAddress; + i8 nodeId; + u8 isConnected; + std::array username; + u8 _pad0_[0x1]; + i16 localCommunicationVersion; + u8 _pad1_[0x10]; + }; + static_assert(sizeof(NodeInfo) == 0x40); + + struct LdnNetworkInfo { + std::array securityParameter; + SecurityMode securityMode; + AcceptPolicy stationAcceptPolicy; + u8 hasActionFrame; + u8 _pad0_[0x2]; + u8 nodeCountMax; + u8 nodeCount; + std::array nodes; + u8 _pad1_[0x2]; + u16 advertiseDataSize; + std::array advertiseData; + u8 _pad2_[0x8C]; + u64 randomAuthenticationId; + }; + static_assert(sizeof(LdnNetworkInfo) == 0x430); + + struct NetworkInfo { + NetworkId networkId; + CommonNetworkInfo common; + LdnNetworkInfo ldn; + }; + static_assert(sizeof(NetworkInfo) == 0x480); + + struct SecurityConfig { + SecurityMode securityMode; + u16 passphraseSize; + std::array passphrase; + }; + static_assert(sizeof(SecurityConfig) == 0x44); + + struct SecurityParameter { + std::array data; + SessionId sessionId; + }; + static_assert(sizeof(SecurityParameter) == 0x20); + + struct UserConfig { + std::array username; + u8 _pad0_[0xF]; + }; + static_assert(sizeof(UserConfig) == 0x30); + + struct NetworkConfig { + IntentId intentId; + WifiChannel channel; + u8 nodeCountMax; + u8 _pad0_[0x1]; + u16 localCommunicationVersion; + u8 _pad1_[0xA]; + }; + static_assert(sizeof(NetworkConfig) == 0x20); + + struct NodeLatestUpdate { + NodeStateChange stateChange; + u8 _pad0_[0x7]; + }; + static_assert(sizeof(NodeLatestUpdate) == 0x8); + /** * @brief IUserLocalCommunicationService is used by applications to manage LDN sessions * @url https://switchbrew.org/wiki/LDN_services#IUserLocalCommunicationService @@ -17,6 +202,7 @@ namespace skyline::service::ldn { class IUserLocalCommunicationService : public BaseService { private: std::shared_ptr event; //!< The KEvent that is signalled on state changes + bool isInitialized{false}; public: IUserLocalCommunicationService(const DeviceState &state, ServiceManager &manager); @@ -26,11 +212,71 @@ namespace skyline::service::ldn { */ Result GetState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @url https://switchbrew.org/wiki/LDN_services#GetNetworkInfo + */ + Result GetNetworkInfo(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#GetIpv4Address + */ + Result GetIpv4Address(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#GetDisconnectReason + */ + Result GetDisconnectReason(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#GetSecurityParameter + */ + Result GetSecurityParameter(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#GetNetworkConfig + */ + Result GetNetworkConfig(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** * @url https://switchbrew.org/wiki/LDN_services#AttachStateChangeEvent */ Result AttachStateChangeEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** + * @url https://switchbrew.org/wiki/LDN_services#GetNetworkInfoLatestUpdate + */ + Result GetNetworkInfoLatestUpdate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#Scan + */ + Result Scan(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#OpenAccessPoint + */ + Result OpenAccessPoint(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#CreateNetwork + */ + Result CreateNetwork(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#CreateNetworkPrivate + */ + Result CreateNetworkPrivate(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#SetAdvertiseData + */ + Result SetAdvertiseData(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + + /** + * @url https://switchbrew.org/wiki/LDN_services#OpenStation + */ + Result OpenStation(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response); + /** * @url https://switchbrew.org/wiki/LDN_services#InitializeSystem */ @@ -48,10 +294,22 @@ namespace skyline::service::ldn { SERVICE_DECL( SFUNC(0x0, IUserLocalCommunicationService, GetState), + SFUNC(0x1, IUserLocalCommunicationService, GetNetworkInfo), + SFUNC(0x2, IUserLocalCommunicationService, GetIpv4Address), + SFUNC(0x3, IUserLocalCommunicationService, GetDisconnectReason), + SFUNC(0x4, IUserLocalCommunicationService, GetSecurityParameter), + SFUNC(0x5, IUserLocalCommunicationService, GetNetworkConfig), SFUNC(0x64, IUserLocalCommunicationService, AttachStateChangeEvent), + SFUNC(0x65, IUserLocalCommunicationService, GetNetworkInfoLatestUpdate), + SFUNC(0x66, IUserLocalCommunicationService, Scan), + SFUNC(0xC8, IUserLocalCommunicationService, OpenAccessPoint), + SFUNC(0xCA, IUserLocalCommunicationService, CreateNetwork), + SFUNC(0xCB, IUserLocalCommunicationService, CreateNetworkPrivate), + SFUNC(0xCE, IUserLocalCommunicationService, SetAdvertiseData), + SFUNC(0x12C, IUserLocalCommunicationService, OpenStation), SFUNC(0x190, IUserLocalCommunicationService, InitializeSystem), SFUNC(0x191, IUserLocalCommunicationService, FinalizeSystem), - SFUNC(0x192, IUserLocalCommunicationService, InitializeSystem2), + SFUNC(0x192, IUserLocalCommunicationService, InitializeSystem2) ) }; }