Skip to content

Commit 70ea18a

Browse files
committed
ldn: Added *ActionFrame, ldnSetHomeChannel, *TxPower.
1 parent 18002c9 commit 70ea18a

File tree

2 files changed

+228
-0
lines changed
  • nx

2 files changed

+228
-0
lines changed

nx/include/switch/services/ldn.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,15 @@ typedef struct {
193193
u8 reserved_x16[0xA]; ///< Cleared to zero for the tmp struct.
194194
} LdnNetworkConfig;
195195

196+
/// ActionFrameSettings
197+
typedef struct {
198+
s64 local_communication_id; ///< LocalCommunicationId (Same handling as LdnNetworkConfig::local_communication_id)
199+
u8 reserved[0x34]; ///< Reserved
200+
u16 security_mode; ///< SecurityMode (Must be 1-2, internally this is overriden)
201+
u16 passphrase_size; ///< PassphraseSize (Must be 0x10-0x40)
202+
u8 passphrase[0x40]; ///< Passphrase
203+
} LdnActionFrameSettings;
204+
196205
///@name ldn:m
197206
///@{
198207

@@ -476,5 +485,71 @@ Result ldnDisconnect(void);
476485
*/
477486
Result ldnSetOperationMode(LdnOperationMode mode);
478487

488+
/**
489+
* @brief EnableActionFrame
490+
* @note Only available on [18.0.0+].
491+
* @note \ref LdnState must be ::LdnState_Initialized.
492+
* @param[in] settings \ref LdnActionFrameSettings
493+
*/
494+
Result ldnEnableActionFrame(const LdnActionFrameSettings *settings);
495+
496+
/**
497+
* @brief DisableActionFrame
498+
* @note Only available on [18.0.0+].
499+
* @note \ref LdnState must be ::LdnState_Initialized.
500+
*/
501+
Result ldnDisableActionFrame(void);
502+
503+
/**
504+
* @brief SendActionFrame
505+
* @note Only available on [18.0.0+].
506+
* @note \ref LdnState must be ::LdnState_AccessPointCreated / ::LdnState_StationOpened.
507+
* @param[in] data Data buffer.
508+
* @param[in] size Data buffer size.
509+
* @param[in] destination Destination \ref LdnMacAddress.
510+
* @param[in] bssid Bssid \ref LdnMacAddress.
511+
* @param[in] channel Channel, must be non-zero.
512+
* @param[in] flags MessageFlag bit0 clear = block until the data can be sent, set = return error when the data can't be sent.
513+
*/
514+
Result ldnSendActionFrame(const void* data, size_t size, LdnMacAddress destination, LdnMacAddress bssid, s16 channel, u32 flags);
515+
516+
/**
517+
* @brief RecvActionFrame
518+
* @note Only available on [18.0.0+].
519+
* @note \ref ldnEnableActionFrame must be used prior to this.
520+
* @param[out] data Output data buffer.
521+
* @param[in] size Max size of the data buffer.
522+
* @param[out] addr0 First \ref LdnMacAddress.
523+
* @param[out] addr1 Second \ref LdnMacAddress.
524+
* @param[out] channel Channel
525+
* @param[out] out_size Output size.
526+
* @param[out] link_level LinkLevel
527+
* @param[in] flags MessageFlag bit0 clear = block until data is available, set = return error when data is not available.
528+
*/
529+
Result ldnRecvActionFrame(void* data, size_t size, LdnMacAddress *addr0, LdnMacAddress *addr1, s16 *channel, u32 *out_size, s32 *link_level, u32 flags);
530+
531+
/**
532+
* @brief SetHomeChannel
533+
* @note Only available on [18.0.0+].
534+
* @note \ref LdnState must be ::LdnState_StationOpened.
535+
* @param[in] channel Channel, must be non-zero.
536+
*/
537+
Result ldnSetHomeChannel(s16 channel);
538+
539+
/**
540+
* @brief SetTxPower
541+
* @note Only available on [18.0.0+].
542+
* @note \ref LdnState must be ::LdnState_AccessPoint* / ::LdnState_Station*.
543+
* @param[in] power Power, must be 0x0..0xFF.
544+
*/
545+
Result ldnSetTxPower(s16 power);
546+
547+
/**
548+
* @brief ResetTxPower
549+
* @note Only available on [18.0.0+].
550+
* @note \ref LdnState must be ::LdnState_AccessPoint* / ::LdnState_Station*.
551+
*/
552+
Result ldnResetTxPower(void);
553+
479554
///@}
480555

nx/source/services/ldn.c

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ static Result _ldnCmdInU32NoOut(Service* srv, u32 in, u32 cmd_id) {
140140
return serviceDispatchIn(srv, cmd_id, in);
141141
}
142142

143+
static Result _ldnCmdInU16NoOut(Service* srv, u16 in, u32 cmd_id) {
144+
return serviceDispatchIn(srv, cmd_id, in);
145+
}
146+
143147
static Result _ldnCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
144148
return serviceDispatchOut(srv, cmd_id, *out);
145149
}
@@ -226,6 +230,26 @@ static void _ldnCopyNetworkConfig(const LdnNetworkConfig *in, LdnNetworkConfig *
226230
out->local_communication_version = in->local_communication_version;
227231
}
228232

233+
static s16 _ldnChannelToOldBand(s16 channel) {
234+
if (channel < 15) return 24;
235+
else return 50;
236+
}
237+
238+
static u16 _ldnChannelToChannelBand(s16 channel) {
239+
if (!channel) return channel;
240+
u16 tmp_channel = channel & 0x3FF; // Official sw just masks with u16.
241+
242+
u16 band = 0x3F; // Invalid
243+
if (tmp_channel < 15) band = 2;
244+
else if (tmp_channel >= 32 && tmp_channel < 178) band = 5;
245+
246+
return channel | (band<<10);
247+
}
248+
249+
static s16 _ldnChannelBandToChannel(u16 val) {
250+
return val & 0x3FF;
251+
}
252+
229253
Result ldnGetState(LdnState *out) {
230254
u32 tmp=0;
231255
Result rc = _ldnCmdNoInOutU32(&g_ldnSrv, &tmp, 0);
@@ -426,3 +450,132 @@ Result ldnSetOperationMode(LdnOperationMode mode) {
426450
return _ldnCmdInU32NoOut(&g_ldnSrv, mode, 402);
427451
}
428452

453+
Result ldnEnableActionFrame(const LdnActionFrameSettings *settings) {
454+
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
455+
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
456+
457+
if (hosversionBefore(18,0,0))
458+
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
459+
460+
return serviceDispatchIn(&g_ldnSrv, 500, *settings);
461+
}
462+
463+
Result ldnDisableActionFrame(void) {
464+
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
465+
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
466+
467+
if (hosversionBefore(18,0,0))
468+
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
469+
470+
return _ldnCmdNoIO(&g_ldnSrv, 501);
471+
}
472+
473+
Result ldnSendActionFrame(const void* data, size_t size, LdnMacAddress destination, LdnMacAddress bssid, s16 channel, u32 flags) {
474+
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
475+
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
476+
477+
if (hosversionBefore(18,0,0))
478+
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
479+
480+
s16 tmp_band = 0, tmp_channel = 0;
481+
if (hosversionBefore(20,0,0)) {
482+
tmp_channel = channel;
483+
tmp_band = _ldnChannelToOldBand(channel);
484+
}
485+
else
486+
tmp_band = _ldnChannelToChannelBand(channel);
487+
488+
const struct {
489+
LdnMacAddress destination;
490+
LdnMacAddress bssid;
491+
s16 band; // These are a single u16 with [20.0.0+].
492+
s16 channel;
493+
u32 flags;
494+
} in = { destination, bssid, tmp_band, tmp_channel, flags};
495+
496+
return serviceDispatchIn(&g_ldnSrv, 502, in,
497+
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_In },
498+
.buffers = { { data, size } },
499+
);
500+
}
501+
502+
Result ldnRecvActionFrame(void* data, size_t size, LdnMacAddress *addr0, LdnMacAddress *addr1, s16 *channel, u32 *out_size, s32 *link_level, u32 flags) {
503+
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
504+
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
505+
506+
if (hosversionBefore(18,0,0))
507+
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
508+
509+
struct {
510+
LdnMacAddress addr0;
511+
LdnMacAddress addr1;
512+
s16 band; // These are a single u16 with [20.0.0+].
513+
s16 channel;
514+
u32 size;
515+
s32 link_level;
516+
} out;
517+
518+
Result rc = serviceDispatchInOut(&g_ldnSrv, 503, flags, out,
519+
.buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out },
520+
.buffers = { { data, size } },
521+
);
522+
if (R_SUCCEEDED(rc)) {
523+
if (addr0) *addr0 = out.addr0;
524+
if (addr1) *addr1 = out.addr1;
525+
if (channel) {
526+
if (hosversionBefore(20,0,0))
527+
*channel = out.channel;
528+
else
529+
*channel = _ldnChannelBandToChannel(out.band);
530+
}
531+
if (out_size) *out_size = out.size;
532+
if (link_level) *link_level = out.link_level;
533+
}
534+
return rc;
535+
}
536+
537+
Result ldnSetHomeChannel(s16 channel) {
538+
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
539+
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
540+
541+
if (hosversionBefore(18,0,0))
542+
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
543+
544+
s16 tmp_band = 0, tmp_channel = 0;
545+
if (hosversionBefore(20,0,0)) {
546+
tmp_channel = channel;
547+
tmp_band = _ldnChannelToOldBand(channel);
548+
549+
const struct {
550+
s16 band;
551+
s16 channel;
552+
} in = { tmp_band, tmp_channel };
553+
554+
return serviceDispatchIn(&g_ldnSrv, 505, in);
555+
}
556+
else
557+
tmp_band = _ldnChannelToChannelBand(channel);
558+
559+
return _ldnCmdInU16NoOut(&g_ldnSrv, tmp_band, 505);
560+
}
561+
562+
Result ldnSetTxPower(s16 power) {
563+
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
564+
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
565+
566+
if (hosversionBefore(18,0,0))
567+
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
568+
569+
return _ldnCmdInU16NoOut(&g_ldnSrv, power, 600);
570+
}
571+
572+
Result ldnResetTxPower(void) {
573+
if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System)
574+
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
575+
576+
if (hosversionBefore(18,0,0))
577+
return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer);
578+
579+
return _ldnCmdNoIO(&g_ldnSrv, 601);
580+
}
581+

0 commit comments

Comments
 (0)