From 9aa9d32e119986476e0691d0f606a9acab13be0c Mon Sep 17 00:00:00 2001 From: yellows8 Date: Mon, 4 Apr 2016 14:26:49 -0400 Subject: [PATCH] Added varioues UDS structs and enums+defines. Implemented udsGenerateDefaultNetworkStruct(). Implemented code for creating+destroying networks. Implemented code for binds. Implemented udsSendTo(). --- libctru/include/3ds/services/uds.h | 104 ++++++++++++++++ libctru/source/services/uds.c | 187 +++++++++++++++++++++++++++++ 2 files changed, 291 insertions(+) diff --git a/libctru/include/3ds/services/uds.h b/libctru/include/3ds/services/uds.h index fc3f864..97666d9 100644 --- a/libctru/include/3ds/services/uds.h +++ b/libctru/include/3ds/services/uds.h @@ -11,6 +11,64 @@ typedef struct { u32 words_x20[2];//Not initialized by DLP-sysmodule. } udsNodeInfo; +/// Network struct stored as big-endian. +typedef struct { + u8 host_macaddress[6]; + u8 unk_x6[2]; + + u8 initialized_flag;//Must be non-zero otherwise NWM-module will use zeros internally instead of the actual field data, for most/all(?) of the fields in this struct. + + u8 unk_x9[3]; + + u8 oui_value[3];//"This is the OUI value for use with the beacon tags. Normally this is 001F32. " + u8 oui_type;//"OUI type (21/0x15)" + + u32 wlancommID;//Unique local-WLAN communications ID for each application. + u8 id8;//Additional ID that can be used by the application for different types of networks. + u8 unk_x15; + + u16 attributes;//See the UDSNETATTR enum values below. + u8 unk_x18[5]; + + u8 max_nodes; + u8 unk_x1e; + u8 unk_x1f; + u8 unk_x20[0x1f]; + + u8 appdata_size; + u8 appdata[0xc8]; +} udsNetworkStruct; + +typedef struct { + u32 BindNodeID; + Handle event; +} udsBindContext; + +enum { + UDSNETATTR_DisableConnectClients = BIT(1), //When set new Clients are not allowed to connect. + UDSNETATTR_DisableConnectSpectators = BIT(2), //When set new Spectators are (probably) not allowed to connect. + UDSNETATTR_Default = BIT(15), //Unknown what this bit is for. +}; + +enum { + UDS_SENDFLAG_Default = BIT(0), //Unknown what this bit is for. + UDS_SENDFLAG_Broadcast = BIT(1) //When set, broadcast the data frame even when UDS_BROADCAST_NETWORKNODEID isn't used. Needs verified. +}; + +typedef enum { + UDSCONTYPE_Client = 0x1, + UDSCONTYPE_Spectator = 0x2 +} udsConnectionType; + +/// Maximum number of nodes(devices) that can be connected to the network. +#define UDS_MAXNODES 16 + +/// Broadcast value for NetworkNodeID / alias for all NetworkNodeIDs. +#define UDS_BROADCAST_NETWORKNODEID 0xFFFF + +/// Default value that can be used for udsSendTo() input8. +#define UDS_SEND_INPUT8_DEFAULT 0x2 + /** * @brief Initializes UDS. * @param sharedmem_size This must be 0x1000-byte aligned. @@ -33,3 +91,49 @@ Result udsGenerateNodeInfo(udsNodeInfo *nodeinfo, const uint8_t *username); */ Result udsGetNodeInfoUsername(udsNodeInfo *nodeinfo, uint8_t *username); +/** + * @brief Generates a default NetworkStruct for creating networks. + * @param network The output struct. + * @param wlancommID Unique local-WLAN communications ID for each application. + * @param id8 Additional ID that can be used by the application for different types of networks. + * @param max_nodes Maximum number of nodes(devices) that can be connected to the network, including the host. + */ +void udsGenerateDefaultNetworkStruct(udsNetworkStruct *network, u32 wlancommID, u8 id8, u8 max_nodes); + +/** + * @brief Create a bind. + * @param bindcontext The output bind context. + * @param NetworkNodeID This is the NetworkNodeID which this bind can receive data from. + */ +Result udsBind(udsBindContext *bindcontext, u16 NetworkNodeID); + +/** + * @brief Remove a bind. + * @param bindcontext The bind context. + */ +Result udsUnbind(udsBindContext *bindcontext); + +/** + * @brief Sends data over the network. + * @param dst_NetworkNodeID Destination NetworkNodeID. + * @param input8 UDS_SEND_INPUT8_DEFAULT can be used for this. It's unknown what this field is actually for. + * @param flags Send flags, see the UDS_SENDFLAG enum values. + * @param buf Input send buffer. + * @param size Size of the buffer. + */ +Result udsSendTo(u16 dst_NetworkNodeID, u8 input8, u8 flags, void* buf, size_t size); + +/** + * @brief Starts hosting a new network. + * @param network The NetworkStruct, you can use udsGenerateDefaultNetworkStruct() for generating this. + * @param passphrase Raw input passphrase buffer. + * @param passphrase_size Size of the passphrase buffer. + * @param bindcontext Output bind context which will be created for this host, with NetworkNodeID=UDS_BROADCAST_NETWORKNODEID. + */ +Result udsCreateNetwork(udsNetworkStruct *network, void* passphrase, size_t passphrase_size, udsBindContext *bindcontext); + +/** + * @brief Stop hosting the network. + */ +Result udsDestroyNetwork(void); + diff --git a/libctru/source/services/uds.c b/libctru/source/services/uds.c index b41dfd3..a76df52 100644 --- a/libctru/source/services/uds.c +++ b/libctru/source/services/uds.c @@ -2,6 +2,7 @@ #include #include #include +#include #include <3ds/types.h> #include <3ds/result.h> #include <3ds/svc.h> @@ -22,10 +23,18 @@ static Handle __uds_sharedmem_handle; static Handle __uds_connectionstatus_event; +static u32 bind_allocbitmask; + static Result uds_Initialize(u32 sharedmem_size, const uint8_t *username); static Result udsipc_InitializeWithVersion(udsNodeInfo *nodeinfo, Handle sharedmem_handle, u32 sharedmem_size, Handle *eventhandle); static Result udsipc_Shutdown(void); +static Result udsipc_BeginHostingNetwork(udsNetworkStruct *network, void* passphrase, size_t passphrase_size); +static Result udsipc_SetProbeResponseParam(u32 oui, s8 data); + +static Result udsipc_Bind(udsBindContext *bindcontext, u32 input0, u8 input1, u16 NetworkNodeID); +static Result udsipc_Unbind(udsBindContext *bindcontext); + Result udsInit(u32 sharedmem_size, const uint8_t *username) { Result ret=0; @@ -69,6 +78,8 @@ Result udsInit(u32 sharedmem_size, const uint8_t *username) AtomicDecrement(&__uds_refcount); } + bind_allocbitmask = 0; + return ret; } @@ -151,6 +162,28 @@ Result udsGetNodeInfoUsername(udsNodeInfo *nodeinfo, uint8_t *username) return 0; } +void udsGenerateDefaultNetworkStruct(udsNetworkStruct *network, u32 wlancommID, u8 id8, u8 max_nodes) +{ + u8 oui_value[3] = {0x00, 0x1f, 0x32}; + + memset(network, 0, sizeof(udsNetworkStruct)); + + network->initialized_flag = 1; + + memcpy(network->oui_value, oui_value, 3); + network->oui_type = 21; + + network->wlancommID = htonl(wlancommID); + network->id8 = id8; + + network->attributes = UDSNETATTR_Default; + + if(max_nodes > UDS_MAXNODES)max_nodes = UDS_MAXNODES; + network->max_nodes = max_nodes; + + network->unk_x1f = 1; +} + static Result uds_Initialize(u32 sharedmem_size, const uint8_t *username) { Result ret=0; @@ -195,6 +228,23 @@ static Result uds_Initialize(u32 sharedmem_size, const uint8_t *username) return ret; } +Result udsCreateNetwork(udsNetworkStruct *network, void* passphrase, size_t passphrase_size, udsBindContext *context) +{ + Result ret=0; + + ret = udsipc_SetProbeResponseParam(0x00210080, 0); + if(R_FAILED(ret))return ret; + + ret = udsipc_BeginHostingNetwork(network, passphrase, passphrase_size); + if(R_FAILED(ret))return ret; + + ret = udsBind(context, UDS_BROADCAST_NETWORKNODEID); + + if(R_FAILED(ret))udsDestroyNetwork(); + + return ret; +} + static Result udsipc_InitializeWithVersion(udsNodeInfo *nodeinfo, Handle sharedmem_handle, u32 sharedmem_size, Handle *eventhandle) { u32* cmdbuf=getThreadCommandBuffer(); @@ -230,3 +280,140 @@ static Result udsipc_Shutdown(void) return cmdbuf[1]; } +Result udsDestroyNetwork(void) +{ + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x8,0,0); // 0x80000 + + Result ret=0; + if(R_FAILED(ret=svcSendSyncRequest(__uds_servhandle)))return ret; + + return cmdbuf[1]; +} + +Result udsBind(udsBindContext *bindcontext, u16 NetworkNodeID) +{ + u32 pos; + + memset(bindcontext, 0, sizeof(udsBindContext)); + + for(pos=0; posBindNodeID = (pos+1)<<1; + + return udsipc_Bind(bindcontext, 0x2e30, 0xf3, NetworkNodeID); +} + +Result udsUnbind(udsBindContext *bindcontext) +{ + Result ret=0; + + if(bindcontext->event) + { + svcCloseHandle(bindcontext->event); + } + + ret = udsipc_Unbind(bindcontext); + + bind_allocbitmask &= ~BIT((bindcontext->BindNodeID>>1) - 1); + + memset(bindcontext, 0, sizeof(udsBindContext)); + + return ret; +} + +static Result udsipc_Bind(udsBindContext *bindcontext, u32 input0, u8 input1, u16 NetworkNodeID)//input0 and input1 are unknown. +{ + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x12,4,0); // 0x120100 + cmdbuf[1]=bindcontext->BindNodeID; + cmdbuf[2]=input0; + cmdbuf[3]=input1; + cmdbuf[4]=NetworkNodeID; + + Result ret=0; + if(R_FAILED(ret=svcSendSyncRequest(__uds_servhandle)))return ret; + ret = cmdbuf[1]; + + if(R_SUCCEEDED(ret)) + { + bindcontext->event = cmdbuf[3]; + } + + return ret; +} + +static Result udsipc_Unbind(udsBindContext *bindcontext) +{ + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x13,1,0); // 0x130040 + cmdbuf[1]=bindcontext->BindNodeID; + + Result ret=0; + if(R_FAILED(ret=svcSendSyncRequest(__uds_servhandle)))return ret; + + return cmdbuf[1]; +} + +Result udsSendTo(u16 dst_NetworkNodeID, u8 input8, u8 flags, void* buf, size_t size) +{ + u32* cmdbuf=getThreadCommandBuffer(); + + u32 aligned_size = (size+0x3) & ~0x3; + + cmdbuf[0]=IPC_MakeHeader(0x17,6,2); // 0x170182 + cmdbuf[1]=0x1;//Unused + cmdbuf[2]=dst_NetworkNodeID; + cmdbuf[3]=input8; + cmdbuf[4]=aligned_size>>2; + cmdbuf[5]=size; + cmdbuf[6]=flags; + cmdbuf[7]=IPC_Desc_StaticBuffer(aligned_size, 5); + cmdbuf[8]=(u32)buf; + + Result ret=0; + if(R_FAILED(ret=svcSendSyncRequest(__uds_servhandle)))return ret; + + return cmdbuf[1]; +} + +static Result udsipc_BeginHostingNetwork(udsNetworkStruct *network, void* passphrase, size_t passphrase_size) +{ + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x1D,1,4); // 0x1D0044 + cmdbuf[1]=passphrase_size; + cmdbuf[2]=IPC_Desc_StaticBuffer(sizeof(udsNetworkStruct), 1); + cmdbuf[3]=(u32)network; + cmdbuf[4]=IPC_Desc_StaticBuffer(passphrase_size, 0); + cmdbuf[5]=(u32)network; + + Result ret=0; + if(R_FAILED(ret=svcSendSyncRequest(__uds_servhandle)))return ret; + + return cmdbuf[1]; +} + +static Result udsipc_SetProbeResponseParam(u32 oui, s8 data) +{ + u32* cmdbuf=getThreadCommandBuffer(); + + cmdbuf[0]=IPC_MakeHeader(0x21,2,0); // 0x210080 + cmdbuf[1]=oui; + cmdbuf[2]=data; + + Result ret=0; + if(R_FAILED(ret=svcSendSyncRequest(__uds_servhandle)))return ret; + + return cmdbuf[1]; +} +