mirror of
https://github.com/skyline-emu/skyline.git
synced 2025-01-08 10:00:43 +01:00
Implement GetCurrentIpConfigInfo
Needed for almost every LAN game
This commit is contained in:
parent
635f06bf50
commit
54041ceba1
@ -3,6 +3,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
|
||||||
<uses-feature
|
<uses-feature
|
||||||
|
@ -64,7 +64,8 @@ namespace skyline {
|
|||||||
closeKeyboardId{environ->GetMethodID(instanceClass, "closeKeyboard", "(Lemu/skyline/applet/swkbd/SoftwareKeyboardDialog;)V")},
|
closeKeyboardId{environ->GetMethodID(instanceClass, "closeKeyboard", "(Lemu/skyline/applet/swkbd/SoftwareKeyboardDialog;)V")},
|
||||||
showValidationResultId{environ->GetMethodID(instanceClass, "showValidationResult", "(Lemu/skyline/applet/swkbd/SoftwareKeyboardDialog;ILjava/lang/String;)I")},
|
showValidationResultId{environ->GetMethodID(instanceClass, "showValidationResult", "(Lemu/skyline/applet/swkbd/SoftwareKeyboardDialog;ILjava/lang/String;)I")},
|
||||||
getVersionCodeId{environ->GetMethodID(instanceClass, "getVersionCode", "()I")},
|
getVersionCodeId{environ->GetMethodID(instanceClass, "getVersionCode", "()I")},
|
||||||
getIntegerValueId{environ->GetMethodID(environ->FindClass("java/lang/Integer"), "intValue", "()I")} {
|
getIntegerValueId{environ->GetMethodID(environ->FindClass("java/lang/Integer"), "intValue", "()I")},
|
||||||
|
getDhcpInfoId{environ->GetMethodID(instanceClass, "getDhcpInfo", "()Landroid/net/DhcpInfo;")} {
|
||||||
env.Initialize(environ);
|
env.Initialize(environ);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +133,23 @@ namespace skyline {
|
|||||||
return {static_cast<KeyboardCloseResult>(env->CallIntMethod(buttonInteger, getIntegerValueId)), input};
|
return {static_cast<KeyboardCloseResult>(env->CallIntMethod(buttonInteger, getIntegerValueId)), input};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DhcpInfo JvmManager::GetDhcpInfo() {
|
||||||
|
jobject dhcpInfo{env->CallObjectMethod(instance, getDhcpInfoId)};
|
||||||
|
jclass dhcpInfoClass{env->GetObjectClass(dhcpInfo)};
|
||||||
|
jfieldID ipAddressFieldId{env->GetFieldID(dhcpInfoClass, "ipAddress", "I")};
|
||||||
|
jfieldID subnetFieldId{env->GetFieldID(dhcpInfoClass, "netmask", "I")};
|
||||||
|
jfieldID gatewayFieldId{env->GetFieldID(dhcpInfoClass, "gateway", "I")};
|
||||||
|
jfieldID dns1FieldId{env->GetFieldID(dhcpInfoClass, "dns1", "I")};
|
||||||
|
jfieldID dns2FieldId{env->GetFieldID(dhcpInfoClass, "dns2", "I")};
|
||||||
|
|
||||||
|
jint ipAddress{env->GetIntField(dhcpInfo, ipAddressFieldId)};
|
||||||
|
jint subnet{env->GetIntField(dhcpInfo, subnetFieldId)};
|
||||||
|
jint gateway{env->GetIntField(dhcpInfo, gatewayFieldId)};
|
||||||
|
jint dns1{env->GetIntField(dhcpInfo, dns1FieldId)};
|
||||||
|
jint dns2{env->GetIntField(dhcpInfo, dns2FieldId)};
|
||||||
|
return DhcpInfo{ipAddress, subnet, gateway, dns1, dns2};
|
||||||
|
}
|
||||||
|
|
||||||
void JvmManager::CloseKeyboard(jobject dialog) {
|
void JvmManager::CloseKeyboard(jobject dialog) {
|
||||||
env->CallVoidMethod(instance, closeKeyboardId, dialog);
|
env->CallVoidMethod(instance, closeKeyboardId, dialog);
|
||||||
env->DeleteGlobalRef(dialog);
|
env->DeleteGlobalRef(dialog);
|
||||||
|
@ -7,6 +7,14 @@
|
|||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
|
||||||
namespace skyline {
|
namespace skyline {
|
||||||
|
struct DhcpInfo {
|
||||||
|
i32 ipAddress;
|
||||||
|
i32 subnet;
|
||||||
|
i32 gateway;
|
||||||
|
i32 dns1;
|
||||||
|
i32 dns2;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A wrapper over std::string that supports construction using a JNI jstring
|
* @brief A wrapper over std::string that supports construction using a JNI jstring
|
||||||
*/
|
*/
|
||||||
@ -182,6 +190,11 @@ namespace skyline {
|
|||||||
*/
|
*/
|
||||||
i32 GetVersionCode();
|
i32 GetVersionCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A call to EmulationActivity.getDhcpInfo in Kotlin
|
||||||
|
*/
|
||||||
|
DhcpInfo GetDhcpInfo();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
jmethodID initializeControllersId;
|
jmethodID initializeControllersId;
|
||||||
jmethodID vibrateDeviceId;
|
jmethodID vibrateDeviceId;
|
||||||
@ -191,6 +204,7 @@ namespace skyline {
|
|||||||
jmethodID closeKeyboardId;
|
jmethodID closeKeyboardId;
|
||||||
jmethodID showValidationResultId;
|
jmethodID showValidationResultId;
|
||||||
jmethodID getVersionCodeId;
|
jmethodID getVersionCodeId;
|
||||||
|
jmethodID getDhcpInfoId;
|
||||||
|
|
||||||
jmethodID getIntegerValueId;
|
jmethodID getIntegerValueId;
|
||||||
};
|
};
|
||||||
|
@ -4,8 +4,22 @@
|
|||||||
#include "IScanRequest.h"
|
#include "IScanRequest.h"
|
||||||
#include "IRequest.h"
|
#include "IRequest.h"
|
||||||
#include "IGeneralService.h"
|
#include "IGeneralService.h"
|
||||||
|
#include <common/settings.h>
|
||||||
|
#include <jvm.h>
|
||||||
|
|
||||||
namespace skyline::service::nifm {
|
namespace skyline::service::nifm {
|
||||||
|
/**
|
||||||
|
* @brief Converts integer value to an array of bytes ordered in little-endian format
|
||||||
|
*/
|
||||||
|
static std::array<u8, 4> ConvertIntToByteArray(i32 value) {
|
||||||
|
std::array<u8, 4> result{};
|
||||||
|
result[0] = value & 0xFF;
|
||||||
|
result[1] = (value >> 8) & 0xFF;
|
||||||
|
result[2] = (value >> 16) & 0xFF;
|
||||||
|
result[3] = (value >> 24) & 0xFF;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
IGeneralService::IGeneralService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
|
IGeneralService::IGeneralService(const DeviceState &state, ServiceManager &manager) : BaseService(state, manager) {}
|
||||||
|
|
||||||
Result IGeneralService::CreateScanRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IGeneralService::CreateScanRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
@ -18,13 +32,89 @@ namespace skyline::service::nifm {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result IGeneralService::GetCurrentNetworkProfile(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
|
if (!(*state.settings->isInternetEnabled))
|
||||||
|
return result::NoInternetConnection;
|
||||||
|
|
||||||
|
const UUID uuid{static_cast<u128>(0xdeadbeef) << 64};
|
||||||
|
auto dhcpInfo{state.jvm->GetDhcpInfo()};
|
||||||
|
|
||||||
|
SfNetworkProfileData networkProfileData{
|
||||||
|
.ipSettingData{
|
||||||
|
.ipAddressSetting{
|
||||||
|
true,
|
||||||
|
.currentAddress{ConvertIntToByteArray(dhcpInfo.ipAddress)},
|
||||||
|
.subnetMask{ConvertIntToByteArray(dhcpInfo.subnet)},
|
||||||
|
.gateway{ConvertIntToByteArray(dhcpInfo.gateway)},
|
||||||
|
},
|
||||||
|
.dnsSetting{
|
||||||
|
true,
|
||||||
|
.primaryDns{ConvertIntToByteArray(dhcpInfo.dns1)},
|
||||||
|
.secondaryDns{ConvertIntToByteArray(dhcpInfo.dns2)},
|
||||||
|
},
|
||||||
|
.proxySetting{
|
||||||
|
false,
|
||||||
|
.port{},
|
||||||
|
.proxyServer{},
|
||||||
|
.automaticAuthEnabled{},
|
||||||
|
.user{},
|
||||||
|
.password{},
|
||||||
|
},
|
||||||
|
1500,
|
||||||
|
},
|
||||||
|
.uuid{uuid},
|
||||||
|
.networkName{"Skyline Network"},
|
||||||
|
.wirelessSettingData{
|
||||||
|
12,
|
||||||
|
.ssid{"Skyline Network"},
|
||||||
|
.passphrase{"skylinepassword"},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
request.outputBuf.at(0).as<SfNetworkProfileData>() = networkProfileData;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
Result IGeneralService::GetCurrentIpAddress(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IGeneralService::GetCurrentIpAddress(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
return result::NoInternetConnection;
|
if (!(*state.settings->isInternetEnabled))
|
||||||
|
return result::NoInternetConnection;
|
||||||
|
|
||||||
|
auto dhcpInfo{state.jvm->GetDhcpInfo()};
|
||||||
|
response.Push(ConvertIntToByteArray(dhcpInfo.ipAddress));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Result IGeneralService::GetCurrentIpConfigInfo(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
|
if (!(*state.settings->isInternetEnabled))
|
||||||
|
return result::NoInternetConnection;
|
||||||
|
|
||||||
|
auto dhcpInfo{state.jvm->GetDhcpInfo()};
|
||||||
|
|
||||||
|
struct IpConfigInfo {
|
||||||
|
IpAddressSetting ipAddressSetting;
|
||||||
|
DnsSetting dnsSetting;
|
||||||
|
};
|
||||||
|
|
||||||
|
IpConfigInfo ipConfigInfo{
|
||||||
|
.ipAddressSetting{
|
||||||
|
true,
|
||||||
|
.currentAddress{ConvertIntToByteArray(dhcpInfo.ipAddress)},
|
||||||
|
.subnetMask{ConvertIntToByteArray(dhcpInfo.subnet)},
|
||||||
|
.gateway{ConvertIntToByteArray(dhcpInfo.gateway)},
|
||||||
|
},
|
||||||
|
.dnsSetting{
|
||||||
|
true,
|
||||||
|
.primaryDns{ConvertIntToByteArray(dhcpInfo.dns1)},
|
||||||
|
.secondaryDns{ConvertIntToByteArray(dhcpInfo.dns2)},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
response.Push(ipConfigInfo);
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result IGeneralService::IsAnyInternetRequestAccepted(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
Result IGeneralService::IsAnyInternetRequestAccepted(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
|
||||||
// We don't emulate networking so always return false
|
response.Push<u8>(*state.settings->isInternetEnabled);
|
||||||
response.Push(false);
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,90 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <services/serviceman.h>
|
#include <services/serviceman.h>
|
||||||
|
#include "common/uuid.h"
|
||||||
|
|
||||||
namespace skyline::service::nifm {
|
namespace skyline::service::nifm {
|
||||||
namespace result {
|
namespace result {
|
||||||
constexpr Result NoInternetConnection{110, 300};
|
constexpr Result NoInternetConnection{110, 300};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct IpAddressSetting {
|
||||||
|
bool isAutomatic{};
|
||||||
|
std::array<u8, 4> currentAddress{};
|
||||||
|
std::array<u8, 4> subnetMask{};
|
||||||
|
std::array<u8, 4> gateway{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(IpAddressSetting) == 0xD);
|
||||||
|
|
||||||
|
struct DnsSetting {
|
||||||
|
bool isAutomatic{};
|
||||||
|
std::array<u8, 4> primaryDns{};
|
||||||
|
std::array<u8, 4> secondaryDns{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(DnsSetting) == 0x9);
|
||||||
|
|
||||||
|
struct ProxySetting {
|
||||||
|
bool enabled{};
|
||||||
|
u8 _pad0_[0x1];
|
||||||
|
u16 port{};
|
||||||
|
std::array<char, 0x64> proxyServer{};
|
||||||
|
bool automaticAuthEnabled{};
|
||||||
|
std::array<char, 0x20> user{};
|
||||||
|
std::array<char, 0x20> password{};
|
||||||
|
u8 _pad1_[0x1];
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ProxySetting) == 0xAA);
|
||||||
|
|
||||||
|
struct IpSettingData {
|
||||||
|
IpAddressSetting ipAddressSetting{};
|
||||||
|
DnsSetting dnsSetting{};
|
||||||
|
ProxySetting proxySetting{};
|
||||||
|
u16 mtu{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(IpSettingData) == 0xC2);
|
||||||
|
|
||||||
|
struct SfWirelessSettingData {
|
||||||
|
u8 ssidLength{};
|
||||||
|
std::array<char, 0x20> ssid{};
|
||||||
|
u8 _unk0_[0x3];
|
||||||
|
std::array<char, 0x41> passphrase{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SfWirelessSettingData) == 0x65);
|
||||||
|
|
||||||
|
struct NifmWirelessSettingData {
|
||||||
|
u8 ssidLength{};
|
||||||
|
std::array<char, 0x21> ssid{};
|
||||||
|
u8 _unk0_[0x1];
|
||||||
|
u8 _pad0_[0x1];
|
||||||
|
u32 _unk1_[0x2];
|
||||||
|
std::array<char, 0x41> passphrase{};
|
||||||
|
u8 _pad1_[0x3];
|
||||||
|
};
|
||||||
|
static_assert(sizeof(NifmWirelessSettingData) == 0x70);
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct SfNetworkProfileData {
|
||||||
|
IpSettingData ipSettingData{};
|
||||||
|
UUID uuid{};
|
||||||
|
std::array<char, 0x40> networkName{};
|
||||||
|
u8 _unk0_[0x4];
|
||||||
|
SfWirelessSettingData wirelessSettingData{};
|
||||||
|
u8 _pad0_[0x1];
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SfNetworkProfileData) == 0x17C);
|
||||||
|
|
||||||
|
struct NifmNetworkProfileData {
|
||||||
|
UUID uuid{};
|
||||||
|
std::array<char, 0x40> networkName{};
|
||||||
|
u32 _unk0_[0x2];
|
||||||
|
u8 _unk1_[0x2];
|
||||||
|
u8 _pad0_[0x2];
|
||||||
|
NifmWirelessSettingData wirelessSettingData{};
|
||||||
|
IpSettingData ipSettingData{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(NifmNetworkProfileData) == 0x18E);
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief IGeneralService is used by applications to control the network connection
|
* @brief IGeneralService is used by applications to control the network connection
|
||||||
* @url https://switchbrew.org/wiki/Network_Interface_services#IGeneralService
|
* @url https://switchbrew.org/wiki/Network_Interface_services#IGeneralService
|
||||||
@ -27,11 +106,21 @@ namespace skyline::service::nifm {
|
|||||||
*/
|
*/
|
||||||
Result CreateRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
Result CreateRequest(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @url https://switchbrew.org/wiki/Network_Interface_services#GetCurrentNetworkProfile
|
||||||
|
*/
|
||||||
|
Result GetCurrentNetworkProfile(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @url https://switchbrew.org/wiki/Network_Interface_services#GetCurrentIpAddress
|
* @url https://switchbrew.org/wiki/Network_Interface_services#GetCurrentIpAddress
|
||||||
*/
|
*/
|
||||||
Result GetCurrentIpAddress(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
Result GetCurrentIpAddress(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @url https://switchbrew.org/wiki/Network_Interface_services#GetCurrentIpConfigInfo
|
||||||
|
*/
|
||||||
|
Result GetCurrentIpConfigInfo(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @url https://switchbrew.org/wiki/Network_Interface_services#IsAnyInternetRequestAccepted
|
* @url https://switchbrew.org/wiki/Network_Interface_services#IsAnyInternetRequestAccepted
|
||||||
*/
|
*/
|
||||||
@ -40,7 +129,9 @@ namespace skyline::service::nifm {
|
|||||||
SERVICE_DECL(
|
SERVICE_DECL(
|
||||||
SFUNC(0x1, IGeneralService, CreateScanRequest),
|
SFUNC(0x1, IGeneralService, CreateScanRequest),
|
||||||
SFUNC(0x4, IGeneralService, CreateRequest),
|
SFUNC(0x4, IGeneralService, CreateRequest),
|
||||||
|
SFUNC(0x5, IGeneralService, GetCurrentNetworkProfile),
|
||||||
SFUNC(0xC, IGeneralService, GetCurrentIpAddress),
|
SFUNC(0xC, IGeneralService, GetCurrentIpAddress),
|
||||||
|
SFUNC(0xF, IGeneralService, GetCurrentIpConfigInfo),
|
||||||
SFUNC(0x15, IGeneralService, IsAnyInternetRequestAccepted)
|
SFUNC(0x15, IGeneralService, IsAnyInternetRequestAccepted)
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -18,6 +18,8 @@ import android.content.res.Configuration
|
|||||||
import android.graphics.PointF
|
import android.graphics.PointF
|
||||||
import android.graphics.drawable.Icon
|
import android.graphics.drawable.Icon
|
||||||
import android.hardware.display.DisplayManager
|
import android.hardware.display.DisplayManager
|
||||||
|
import android.net.DhcpInfo
|
||||||
|
import android.net.wifi.WifiManager
|
||||||
import android.os.*
|
import android.os.*
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.util.Rational
|
import android.util.Rational
|
||||||
@ -626,6 +628,12 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
|||||||
return dialog.waitForSubmitOrCancel().let { arrayOf(if (it.cancelled) 1 else 0, it.text) }
|
return dialog.waitForSubmitOrCancel().let { arrayOf(if (it.cancelled) 1 else 0, it.text) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
fun getDhcpInfo() : DhcpInfo {
|
||||||
|
val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||||
|
return wifiManager.dhcpInfo
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun closeKeyboard(dialog : SoftwareKeyboardDialog) {
|
fun closeKeyboard(dialog : SoftwareKeyboardDialog) {
|
||||||
runOnUiThread { dialog.dismiss() }
|
runOnUiThread { dialog.dismiss() }
|
||||||
|
Loading…
Reference in New Issue
Block a user