ldn: Added *ActionFrame, ldnSetHomeChannel, *TxPower.

This commit is contained in:
yellows8 2025-06-30 15:48:05 -04:00
parent 18002c9735
commit 70ea18a477
No known key found for this signature in database
GPG Key ID: 0AF90DA3F1E60E43
2 changed files with 228 additions and 0 deletions

View File

@ -193,6 +193,15 @@ typedef struct {
u8 reserved_x16[0xA]; ///< Cleared to zero for the tmp struct.
} LdnNetworkConfig;
/// ActionFrameSettings
typedef struct {
s64 local_communication_id; ///< LocalCommunicationId (Same handling as LdnNetworkConfig::local_communication_id)
u8 reserved[0x34]; ///< Reserved
u16 security_mode; ///< SecurityMode (Must be 1-2, internally this is overriden)
u16 passphrase_size; ///< PassphraseSize (Must be 0x10-0x40)
u8 passphrase[0x40]; ///< Passphrase
} LdnActionFrameSettings;
///@name ldn:m
///@{
@ -476,5 +485,71 @@ Result ldnDisconnect(void);
*/
Result ldnSetOperationMode(LdnOperationMode mode);
/**
* @brief EnableActionFrame
* @note Only available on [18.0.0+].
* @note \ref LdnState must be ::LdnState_Initialized.
* @param[in] settings \ref LdnActionFrameSettings
*/
Result ldnEnableActionFrame(const LdnActionFrameSettings *settings);
/**
* @brief DisableActionFrame
* @note Only available on [18.0.0+].
* @note \ref LdnState must be ::LdnState_Initialized.
*/
Result ldnDisableActionFrame(void);
/**
* @brief SendActionFrame
* @note Only available on [18.0.0+].
* @note \ref LdnState must be ::LdnState_AccessPointCreated / ::LdnState_StationOpened.
* @param[in] data Data buffer.
* @param[in] size Data buffer size.
* @param[in] destination Destination \ref LdnMacAddress.
* @param[in] bssid Bssid \ref LdnMacAddress.
* @param[in] channel Channel, must be non-zero.
* @param[in] flags MessageFlag bit0 clear = block until the data can be sent, set = return error when the data can't be sent.
*/
Result ldnSendActionFrame(const void* data, size_t size, LdnMacAddress destination, LdnMacAddress bssid, s16 channel, u32 flags);
/**
* @brief RecvActionFrame
* @note Only available on [18.0.0+].
* @note \ref ldnEnableActionFrame must be used prior to this.
* @param[out] data Output data buffer.
* @param[in] size Max size of the data buffer.
* @param[out] addr0 First \ref LdnMacAddress.
* @param[out] addr1 Second \ref LdnMacAddress.
* @param[out] channel Channel
* @param[out] out_size Output size.
* @param[out] link_level LinkLevel
* @param[in] flags MessageFlag bit0 clear = block until data is available, set = return error when data is not available.
*/
Result ldnRecvActionFrame(void* data, size_t size, LdnMacAddress *addr0, LdnMacAddress *addr1, s16 *channel, u32 *out_size, s32 *link_level, u32 flags);
/**
* @brief SetHomeChannel
* @note Only available on [18.0.0+].
* @note \ref LdnState must be ::LdnState_StationOpened.
* @param[in] channel Channel, must be non-zero.
*/
Result ldnSetHomeChannel(s16 channel);
/**
* @brief SetTxPower
* @note Only available on [18.0.0+].
* @note \ref LdnState must be ::LdnState_AccessPoint* / ::LdnState_Station*.
* @param[in] power Power, must be 0x0..0xFF.
*/
Result ldnSetTxPower(s16 power);
/**
* @brief ResetTxPower
* @note Only available on [18.0.0+].
* @note \ref LdnState must be ::LdnState_AccessPoint* / ::LdnState_Station*.
*/
Result ldnResetTxPower(void);
///@}

View File

@ -140,6 +140,10 @@ static Result _ldnCmdInU32NoOut(Service* srv, u32 in, u32 cmd_id) {
return serviceDispatchIn(srv, cmd_id, in);
}
static Result _ldnCmdInU16NoOut(Service* srv, u16 in, u32 cmd_id) {
return serviceDispatchIn(srv, cmd_id, in);
}
static Result _ldnCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
@ -226,6 +230,26 @@ static void _ldnCopyNetworkConfig(const LdnNetworkConfig *in, LdnNetworkConfig *
out->local_communication_version = in->local_communication_version;
}
static s16 _ldnChannelToOldBand(s16 channel) {
if (channel < 15) return 24;
else return 50;
}
static u16 _ldnChannelToChannelBand(s16 channel) {
if (!channel) return channel;
u16 tmp_channel = channel & 0x3FF; // Official sw just masks with u16.
u16 band = 0x3F; // Invalid
if (tmp_channel < 15) band = 2;
else if (tmp_channel >= 32 && tmp_channel < 178) band = 5;
return channel | (band<<10);
}
static s16 _ldnChannelBandToChannel(u16 val) {
return val & 0x3FF;
}
Result ldnGetState(LdnState *out) {
u32 tmp=0;
Result rc = _ldnCmdNoInOutU32(&g_ldnSrv, &tmp, 0);
@ -426,3 +450,132 @@ Result ldnSetOperationMode(LdnOperationMode mode) {
return _ldnCmdInU32NoOut(&g_ldnSrv, mode, 402);
}
Result ldnEnableActionFrame(const LdnActionFrameSettings *settings) {
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(18,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return serviceDispatchIn(&g_ldnSrv, 500, *settings);
}
Result ldnDisableActionFrame(void) {
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(18,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _ldnCmdNoIO(&g_ldnSrv, 501);
}
Result ldnSendActionFrame(const void* data, size_t size, LdnMacAddress destination, LdnMacAddress bssid, s16 channel, u32 flags) {
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(18,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
s16 tmp_band = 0, tmp_channel = 0;
if (hosversionBefore(20,0,0)) {
tmp_channel = channel;
tmp_band = _ldnChannelToOldBand(channel);
}
else
tmp_band = _ldnChannelToChannelBand(channel);
const struct {
LdnMacAddress destination;
LdnMacAddress bssid;
s16 band; // These are a single u16 with [20.0.0+].
s16 channel;
u32 flags;
} in = { destination, bssid, tmp_band, tmp_channel, flags};
return serviceDispatchIn(&g_ldnSrv, 502, in,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_In },
.buffers = { { data, size } },
);
}
Result ldnRecvActionFrame(void* data, size_t size, LdnMacAddress *addr0, LdnMacAddress *addr1, s16 *channel, u32 *out_size, s32 *link_level, u32 flags) {
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(18,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
struct {
LdnMacAddress addr0;
LdnMacAddress addr1;
s16 band; // These are a single u16 with [20.0.0+].
s16 channel;
u32 size;
s32 link_level;
} out;
Result rc = serviceDispatchInOut(&g_ldnSrv, 503, flags, out,
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
.buffers = { { data, size } },
);
if (R_SUCCEEDED(rc)) {
if (addr0) *addr0 = out.addr0;
if (addr1) *addr1 = out.addr1;
if (channel) {
if (hosversionBefore(20,0,0))
*channel = out.channel;
else
*channel = _ldnChannelBandToChannel(out.band);
}
if (out_size) *out_size = out.size;
if (link_level) *link_level = out.link_level;
}
return rc;
}
Result ldnSetHomeChannel(s16 channel) {
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(18,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
s16 tmp_band = 0, tmp_channel = 0;
if (hosversionBefore(20,0,0)) {
tmp_channel = channel;
tmp_band = _ldnChannelToOldBand(channel);
const struct {
s16 band;
s16 channel;
} in = { tmp_band, tmp_channel };
return serviceDispatchIn(&g_ldnSrv, 505, in);
}
else
tmp_band = _ldnChannelToChannelBand(channel);
return _ldnCmdInU16NoOut(&g_ldnSrv, tmp_band, 505);
}
Result ldnSetTxPower(s16 power) {
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(18,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _ldnCmdInU16NoOut(&g_ldnSrv, power, 600);
}
Result ldnResetTxPower(void) {
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
if (hosversionBefore(18,0,0))
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
return _ldnCmdNoIO(&g_ldnSrv, 601);
}