From 68c60ac2d7de8a17b06f6b4fa2bbe775b055c53c Mon Sep 17 00:00:00 2001 From: GaryOderNichts <12049776+GaryOderNichts@users.noreply.github.com> Date: Sat, 11 Feb 2023 02:22:14 +0100 Subject: [PATCH] Add DK_PCHAR support to /dev/iosuhax --- source/ios_kernel/source/instant_patches.c | 4 +- source/ios_kernel/source/ios_mcp_patches.c | 3 +- source/ios_mcp/imports.ld | 66 ++++ source/ios_mcp/link.ld | 4 +- source/ios_mcp/source/dk.c | 370 +++++++++++++++++++++ source/ios_mcp/source/dk.h | 47 +++ source/ios_mcp/source/imports.c | 48 --- source/ios_mcp/source/imports.h | 28 +- source/ios_mcp/source/ipc.c | 100 +++--- source/ios_mcp/source/ipc_types.h | 11 +- source/ios_mcp/source/main.c | 1 - source/ios_mcp/source/mcp_loadfile.c | 6 +- source/ios_mcp/source/smd.c | 320 ++++++++++++++++++ source/ios_mcp/source/smd.h | 128 +++++++ source/ios_mcp/source/socket.c | 24 ++ source/ios_mcp/source/socket.h | 43 +-- 16 files changed, 1082 insertions(+), 121 deletions(-) create mode 100644 source/ios_mcp/imports.ld create mode 100644 source/ios_mcp/source/dk.c create mode 100644 source/ios_mcp/source/dk.h create mode 100644 source/ios_mcp/source/smd.c create mode 100644 source/ios_mcp/source/smd.h diff --git a/source/ios_kernel/source/instant_patches.c b/source/ios_kernel/source/instant_patches.c index 3aa48c7..d620511 100644 --- a/source/ios_kernel/source/instant_patches.c +++ b/source/ios_kernel/source/instant_patches.c @@ -108,7 +108,7 @@ void instant_patches_setup(void) { // Place the environment path at the end of our .text section. for (int i = 0; i < 0x100; i += 4) { - *(volatile u32 *) (0x05119F00 - 0x05100000 + 0x13D80000 + i) = *(volatile u32 *) (0x0017FEF0 + i); + *(volatile u32 *) (0x0511FF00 - 0x05100000 + 0x13D80000 + i) = *(volatile u32 *) (0x0017FEF0 + i); } // force check USB storage on load @@ -134,7 +134,7 @@ void instant_patches_setup(void) { map_info.paddr = 0x05116000 - 0x05100000 + 0x13D80000; map_info.vaddr = 0x05116000; - map_info.size = 0x4000; + map_info.size = 0xA000; map_info.domain = 1; // MCP map_info.type = 3; // 0 = undefined, 1 = kernel only, 2 = read only, 3 = read write map_info.cached = 0xFFFFFFFF; diff --git a/source/ios_kernel/source/ios_mcp_patches.c b/source/ios_kernel/source/ios_mcp_patches.c index 79a6780..9d4774c 100644 --- a/source/ios_kernel/source/ios_mcp_patches.c +++ b/source/ios_kernel/source/ios_mcp_patches.c @@ -22,7 +22,6 @@ * distribution. ***************************************************************************/ #include "ios_mcp_patches.h" -#include "../../ios_mcp/ios_mcp.bin.h" #include "../../ios_mcp/ios_mcp_syms.h" #include "elf_patcher.h" #include "types.h" @@ -41,7 +40,7 @@ void mcp_run_patches(u32 ios_elf_start) { section_write_bss(ios_elf_start, _bss_start, _bss_end - _bss_start); // We can't use "_text_end" here because we need to copy the full 0x4000 to preserve the envrionmen path which // is at the end of the .text section. - section_write(ios_elf_start, _text_start, (void *) mcp_get_phys_code_base(), 0x4000); + section_write(ios_elf_start, _text_start, (void *) mcp_get_phys_code_base(), 0xA000); u32 patch_count = (u32) (((u8 *) mcp_patches_table_end) - ((u8 *) mcp_patches_table)) / sizeof(patch_table_t); patch_table_entries(ios_elf_start, mcp_patches_table, patch_count); diff --git a/source/ios_mcp/imports.ld b/source/ios_mcp/imports.ld new file mode 100644 index 0000000..8cc0168 --- /dev/null +++ b/source/ios_mcp/imports.ld @@ -0,0 +1,66 @@ +PROVIDE(printf = 0x0503dcc0); +/* PROVIDE(printf = 0x05055438); */ +PROVIDE(memcmp = 0x05054d6c); +PROVIDE(memcpy = 0x05054e54); +PROVIDE(memset = 0x05054ef0); +PROVIDE(vsnprintf = 0x05055c40); +/*PROVIDE(snprintf = 0x05055c8c);*/ +PROVIDE(strncpy = 0x05055db4); +PROVIDE(strnlen = 0x05055e94); +PROVIDE(strncmp = 0x05055e10); +PROVIDE(usleep = 0x050564e4); + +PROVIDE(bspWrite = 0x0503d460); +PROVIDE(bspRead = 0x0503d550); + +PROVIDE(UCWriteSysConfig = 0x05044a8c); +PROVIDE(UCReadSysConfig = 0x05044d5c); +PROVIDE(UCClose = 0x05045024); +PROVIDE(UCOpen = 0x05045028); + +PROVIDE(IOS_CreateThread = 0x050567ec); +PROVIDE(IOS_JoinThread = 0x050567f4); +PROVIDE(IOS_CancelThread = 0x050567fc); +PROVIDE(IOS_StartThread = 0x05056824); +PROVIDE(IOS_GetThreadPriority = 0x0505683c); + +PROVIDE(IOS_CreateMessageQueue = 0x0505684c); +PROVIDE(IOS_DestroyMessageQueue = 0x05056854); +PROVIDE(IOS_ReceiveMessage = 0x0505686c); + +PROVIDE(IOS_CreateTimer = 0x05056884); +PROVIDE(IOS_RestartTimer = 0x0505688c); +PROVIDE(IOS_StopTimer = 0x05056894); +PROVIDE(IOS_DestroyTimer = 0x0505689c); + +PROVIDE(IOS_CheckDebugMode = 0x050568ec); +PROVIDE(IOS_ReadOTP = 0x050568fc); + +PROVIDE(IOS_HeapAlloc = 0x05056924); +PROVIDE(IOS_HeapAllocAligned = 0x0505692c); +PROVIDE(IOS_HeapFree = 0x05056934); + +PROVIDE(IOS_Open = 0x05056984); +PROVIDE(IOS_Close = 0x0505698c); +PROVIDE(IOS_Ioctl = 0x050569ac); +PROVIDE(IOS_Ioctlv = 0x050569b4); +PROVIDE(IOS_IoctlvAsync = 0x050569ec); + +PROVIDE(IOS_InvalidateDCache = 0x05056a74); +PROVIDE(IOS_FlushDCache = 0x05056a7c); + +PROVIDE(IOS_CreateSemaphore = 0x05056aa4); +PROVIDE(IOS_WaitSemaphore = 0x05056aac); +PROVIDE(IOS_SignalSemaphore = 0x05056ab4); +PROVIDE(IOS_DestroySempahore = 0x05056abc); + +PROVIDE(IOS_VirtToPhys = 0x05056a9c); + +PROVIDE(IOS_CheckIOPAddressRange = 0x05056ad4); + +PROVIDE(IOS_Shutdown = 0x05056b7c); +PROVIDE(IOS_Syscall0x81 = 0x05056bf4); + +PROVIDE(ppcHeartBeatThreadId = 0x05070458); +PROVIDE(currentColdbootOS = 0x050b8174); +PROVIDE(currentColdbootTitle = 0x050b817c); diff --git a/source/ios_mcp/link.ld b/source/ios_mcp/link.ld index 2bd0ab5..6ca74b6 100644 --- a/source/ios_mcp/link.ld +++ b/source/ios_mcp/link.ld @@ -1,5 +1,7 @@ OUTPUT_ARCH(arm) +INCLUDE "imports.ld" + PROVIDE(snprintf = 0x05059010); SECTIONS @@ -22,6 +24,6 @@ SECTIONS } } -ASSERT((SIZEOF(.text)) < 0x3F00, "text section is too big"); +ASSERT((SIZEOF(.text)) < 0x9F00, "text section is too big"); ASSERT((SIZEOF(.bss)) < 0x3000, "bss section is too big"); diff --git a/source/ios_mcp/source/dk.c b/source/ios_mcp/source/dk.c new file mode 100644 index 0000000..a9d4694 --- /dev/null +++ b/source/ios_mcp/source/dk.c @@ -0,0 +1,370 @@ +#include "dk.h" +#include "imports.h" +#include "smd.h" +#include "socket.h" +#include "svc.h" + +#include +#include +#include + +//#define DEBUG_LOGGING + +#define DK_PORT 3000 +#define DK_THREAD_INTERVAL 600 + +#define DK_SMD_IDX_READ 0 +#define DK_SMD_IDX_WRITE 1 + +static u8 threadStack[0x500] __attribute__((aligned(0x20))); +static int threadRunning = 0; +static int threadId = 0; +static int servfd = 0; + +static int setupServer(int port) { + if (socketInit() < 0) { + printf("DK: failed to init socketlib\n"); + smdIopClose(DK_SMD_IDX_READ); + smdIopClose(DK_SMD_IDX_WRITE); + return -1; + } + + printf("DK: socket init\n"); + + int sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + printf("DK: failed to create socket\n"); + smdIopClose(DK_SMD_IDX_READ); + smdIopClose(DK_SMD_IDX_WRITE); + return -1; + } + + printf("DK: socket created\n"); + + int reuse = 1; + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) { + printf("DK warning: failed to set SO_REUSEADDR\n"); + } + + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = INADDR_ANY; + servaddr.sin_port = port; + if (bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) != 0) { + printf("DK: failed to bind socket\n"); + goto quit; + } + + printf("DK: socket bound\n"); + + return sockfd; + +quit:; + closesocket(sockfd); + return -1; +} + +static int handleServer(int connfd) { + int nonblock = 1; + if (setsockopt(connfd, SOL_SOCKET, SO_NONBLOCK, &nonblock, sizeof(nonblock)) < 0) { + printf("DK: failed to make connection non-blocking\n"); + return 0; + } + + int sack = 1; + if (setsockopt(connfd, SOL_SOCKET, SO_TCPSACK, &sack, sizeof(sack)) < 0) { + printf("DK: failed to set SO_TCPSACK\n"); + return 0; + } + + int nodelay = 1; + if (setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)) < 0) { + printf("DK: failed to set TCP_NODELAY\n"); + return 0; + } + + // create a message queue and timer + uint32_t messageBuf; + int queueId = IOS_CreateMessageQueue(&messageBuf, 1); + if (queueId < 0) { + printf("DK: failed to create message queue\n"); + return -1; + } + + int timerId = IOS_CreateTimer(0, 0, queueId, 0xdeafcafe); + if (timerId < 0) { + printf("DK: failed to create timer\n"); + IOS_DestroyMessageQueue(queueId); + return -1; + } + + while (threadRunning) { + // restart timer + if (IOS_RestartTimer(timerId, DK_THREAD_INTERVAL, 0)) { + printf("DK: failed to restart timer\n"); + break; + } + + // wait until the timer sends a message + uint32_t message; + if (IOS_ReceiveMessage(queueId, &message, 0) < 0) { + printf("DK: failed to receive message\n"); + break; + } + + SmdInterfaceState readState; + if (smdIopGetInterfaceState(DK_SMD_IDX_READ, NULL, &readState) != 0) { + printf("DK: Failed to get interface state, closing...\n"); + break; + } + + SmdInterfaceState writeState; + if (smdIopGetInterfaceState(DK_SMD_IDX_WRITE, NULL, &writeState) != 0) { + printf("DK: Failed to get interface state, closing...\n"); + break; + } + + if (readState != SMD_INTERFACE_STATE_OPENED || writeState != SMD_INTERFACE_STATE_OPENED) { + printf("DK: Closing interfaces\n"); + break; + } + + // process up to 100 writes before waiting + for (int i = 0; i < 100; ++i) { + SmdReceiveData receiveData; + if (smdIopReceive(DK_SMD_IDX_WRITE, &receiveData) != 0) { + break; + } + +#ifdef DEBUG_LOGGING + printf("DK: received write vector\n"); +#endif + + if (receiveData.type != SMD_ELEMENT_TYPE_VECTOR) { + printf("DK Warn: Received smd type %ld on write queue\n", receiveData.type); + continue; + } + + if (receiveData.vector->id != DK_PCHAR_COMMAND_WRITE) { + printf("DK Warn: Received command %lx on write queue\n", receiveData.vector->id); + smdIopSendVector(DK_SMD_IDX_WRITE, receiveData.vector); + continue; + } + + DKPCHARResult *result = receiveData.vector->vecs[0].ptr; + DKPCHARResponse *response = receiveData.vector->vecs[2].ptr; + + response->buf = receiveData.vector->vecs[1].ptr; + + // send data + int32_t error = 0; + uint32_t to_send = receiveData.vector->vecs[1].size; + +#ifdef DEBUG_LOGGING + printf("DK: sending %lu bytes\n", to_send); +#endif + + uint32_t offset = 0; + while (to_send > 0) { + int res = send(connfd, receiveData.vector->vecs[1].ptr + offset, to_send, 0); + if (res < 0) { + error = res; + break; + } + + to_send -= res; + offset += res; + } + + result->error = error; + smdIopSendVector(DK_SMD_IDX_WRITE, receiveData.vector); + } + + // read pending data, if we have any + for (int i = 0; i < 100; ++i) { + char buf[500]; + int32_t res = recv(connfd, buf, sizeof(buf), 0); + if (res == -0xafffa /*EWOULDBLOCK*/) { + // no more data to receive + break; + } + + if (res < 0) { + printf("DK: recv returned %lx\n", res); + break; + } + + if (res == 0) { + printf("DK: client disconnected\n"); + IOS_DestroyTimer(timerId); + IOS_DestroyMessageQueue(queueId); + return 0; + } + +#ifdef DEBUG_LOGGING + printf("DK: recv: %ld\n", res); +#endif + + SmdReceiveData receiveData; + if (smdIopReceive(DK_SMD_IDX_READ, &receiveData) != 0) { + printf("DK Warn: no vector in read queue, dropping packet\n"); + break; + } + +#ifdef DEBUG_LOGGING + printf("DK: received read vector\n"); +#endif + + if (receiveData.type != SMD_ELEMENT_TYPE_VECTOR) { + printf("DK Warn: Received smd type %ld on read queue\n", receiveData.type); + continue; + } + + if (receiveData.vector->id != DK_PCHAR_COMMAND_READ) { + printf("DK Warn: Received command %lx on read queue\n", receiveData.vector->id); + smdIopSendVector(DK_SMD_IDX_READ, receiveData.vector); + continue; + } + + DKPCHARResult *result = receiveData.vector->vecs[0].ptr; + DKPCHARResponse *response = receiveData.vector->vecs[2].ptr; + + response->buf = receiveData.vector->vecs[1].ptr; + + if (receiveData.vector->vecs[1].size < (uint32_t) res) { + printf("DK: Warning truncating received data\n"); + res = receiveData.vector->vecs[1].size; + } + + if (res > 0) { + memcpy(receiveData.vector->vecs[1].ptr, buf, res); + result->error = 0; + result->param0 = res; + } else { + result->error = res; + } + + smdIopSendVector(DK_SMD_IDX_READ, receiveData.vector); + } + } + + IOS_DestroyTimer(timerId); + IOS_DestroyMessageQueue(queueId); + + return -1; +} + +static int dkThread(void *arg) { + printf("DK: thread started\n"); + threadRunning = 1; + + servfd = setupServer(DK_PORT); + if (servfd < 0) { + goto exit; + } + + while (threadRunning) { + if (listen(servfd, 1) != 0) { + printf("DK: failed listening for connections\n"); + goto exit; + } + + printf("DK: listening for connections on port %d\n", DK_PORT); + + struct sockaddr_in clientaddr; + socklen_t len = sizeof(clientaddr); + int connfd = accept(servfd, (struct sockaddr *) &clientaddr, &len); + if (connfd < 0) { + printf("DK: failed to accept connection\n"); + continue; + } + + uint8_t *addr = (uint8_t *) &clientaddr.sin_addr.s_addr; + printf("DK: Connected to %d.%d.%d.%d\n", addr[0], addr[1], addr[2], addr[3]); + + if (handleServer(connfd) < 0) { + closesocket(connfd); + break; + } + + closesocket(connfd); + } + +exit:; + printf("DK: exited thread\n"); + if (servfd >= 0) { + closesocket(servfd); + servfd = -1; + } + + // close smd + smdIopClose(DK_SMD_IDX_READ); + smdIopClose(DK_SMD_IDX_WRITE); + + threadRunning = 0; + return 0; +} + +static void dkPCHARDeactivateSmd() { + // close server socket and tell thread to stop + if (servfd >= 0) { + closesocket(servfd); + servfd = -1; + } + + threadRunning = 0; + + // wait for thread to return + IOS_JoinThread(threadId, NULL); +} + +int dkPCHARActivateSmd(IOSVec *vecs) { + int32_t ret = 0; + DKPCHARResult *result = (DKPCHARResult *) vecs[0].ptr; + DKPCHARActivateParams *params = (DKPCHARActivateParams *) vecs[1].ptr; + + printf("PCHAR Activate (%lx) for %s: SMDs %s %s\n", params->command, params->path, params->smdReadName, params->smdWriteName); + + // Prevent starting another thread while the old one is still running + if (threadRunning) { + printf("DK: thread is already running, stopping...\n"); + dkPCHARDeactivateSmd(); + } + + ret = smdIopInit(DK_SMD_IDX_WRITE, (SmdControlTable *) vecs[2].ptr, params->smdWriteName, 0); + if (ret != 0) { + goto done; + } + + ret = smdIopInit(DK_SMD_IDX_READ, (SmdControlTable *) vecs[3].ptr, params->smdReadName, 0); + if (ret != 0) { + goto done; + } + + ret = smdIopOpen(DK_SMD_IDX_WRITE); + if (ret != 0) { + goto done; + } + + ret = smdIopOpen(DK_SMD_IDX_READ); + if (ret != 0) { + goto done; + } + + threadId = svcCreateThread(dkThread, 0, (u32 *) (threadStack + sizeof(threadStack)), sizeof(threadStack), 0x77, 0); + if (threadId < 0) { + ret = threadId; + goto done; + } + + if (svcStartThread(threadId) < 0) { + printf("DK: failed to start thread\n"); + ret = -11; + } + +done:; + printf("PCHAR Activate %lx\n", ret); + result->error = ret; + return ret; +} diff --git a/source/ios_mcp/source/dk.h b/source/ios_mcp/source/dk.h new file mode 100644 index 0000000..1263c35 --- /dev/null +++ b/source/ios_mcp/source/dk.h @@ -0,0 +1,47 @@ +#pragma once + +#include "ipc_types.h" +#include +#include + +#ifndef PACKED +#define PACKED __attribute__((__packed__)) +#endif + +#ifndef CHECK_SIZE +#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, #type " must be " #size " bytes") +#endif + +enum DKPCHARCommand { + DK_PCHAR_COMMAND_READ = 0x40, + DK_PCHAR_COMMAND_WRITE = 0x41, +}; + +typedef struct PACKED { + uint32_t command; + uint8_t __unk[0x8]; + char path[0x20]; + uint8_t __padding[0x4]; + char smdWriteName[0x10]; + char smdReadName[0x10]; +} DKPCHARActivateParams; +CHECK_SIZE(DKPCHARActivateParams, 0x50); + +typedef struct PACKED { + int32_t error; + uint32_t param0; + uint32_t param1; +} DKPCHARResult; +CHECK_SIZE(DKPCHARResult, 0xC); + +typedef struct PACKED { + uint32_t command; + void *message; + uint32_t unk; + void *buf; + uint32_t size; + uint8_t __padding[0x3C]; +} DKPCHARResponse; +CHECK_SIZE(DKPCHARResponse, 0x50); + +int dkPCHARActivateSmd(IOSVec *vecs); diff --git a/source/ios_mcp/source/imports.c b/source/ios_mcp/source/imports.c index ee6ec76..07a09db 100644 --- a/source/ios_mcp/source/imports.c +++ b/source/ios_mcp/source/imports.c @@ -1,25 +1,5 @@ #include "imports.h" -void usleep(u32 time) { - ((void (*const)(u32)) 0x050564E4)(time); -} - -void *memset(void *dst, int val, size_t size) { - char *_dst = dst; - - int i; - for (i = 0; i < size; i++) - _dst[i] = val; - - return dst; -} - -void *(*const _memcpy)(void *dst, void *src, int size) = (void *) 0x05054E54; - -void *memcpy(void *dst, const void *src, size_t size) { - return _memcpy(dst, (void *) src, size); -} - int strlen(const char *str) { unsigned int i = 0; while (str[i]) { @@ -28,19 +8,6 @@ int strlen(const char *str) { return i; } -int strncmp(const char *s1, const char *s2, size_t n) { - while (n && *s1 && (*s1 == *s2)) { - ++s1; - ++s2; - --n; - } - if (n == 0) { - return 0; - } else { - return (*(unsigned char *) s1 - *(unsigned char *) s2); - } -} - // Function to implement strncat() function in C char *strncat(char *destination, const char *source, size_t num) { // make ptr point to the end of destination string @@ -56,18 +23,3 @@ char *strncat(char *destination, const char *source, size_t num) { // destination string is returned by standard strncat() return destination; } - -char *strncpy(char *dst, const char *src, size_t size) { - int i; - for (i = 0; i < size; i++) { - dst[i] = src[i]; - if (src[i] == '\0') - return dst; - } - - return dst; -} - -int vsnprintf(char *s, size_t n, const char *format, va_list arg) { - return ((int (*const)(char *, size_t, const char *, va_list)) 0x05055C40)(s, n, format, arg); -} diff --git a/source/ios_mcp/source/imports.h b/source/ios_mcp/source/imports.h index d110b37..21d46ce 100644 --- a/source/ios_mcp/source/imports.h +++ b/source/ios_mcp/source/imports.h @@ -7,6 +7,32 @@ #define MCP_SVC_BASE ((void *) 0x050567EC) -void usleep(u32 time); +typedef enum { + MEM_PERM_R = 1 << 0, + MEM_PERM_W = 1 << 1, + MEM_PERM_RW = (MEM_PERM_R | MEM_PERM_W), +} MemPermFlags; + +int IOS_JoinThread(int threadid, int32_t *returned_value); + +int IOS_CreateMessageQueue(uint32_t *ptr, uint32_t n_msgs); +int IOS_DestroyMessageQueue(int queueid); +int IOS_SendMessage(int queueid, uint32_t message, uint32_t flags); +int IOS_ReceiveMessage(int queueid, uint32_t *message, uint32_t flags); + +int IOS_CreateTimer(uint32_t time_us, uint32_t repeat_time_us, int queueid, uint32_t message); +int IOS_RestartTimer(int timerid, uint32_t time_us, uint32_t repeat_time_us); +int IOS_DestroyTimer(int timerid); + +void IOS_InvalidateDCache(void *ptr, uint32_t len); +void IOS_FlushDCache(void *ptr, uint32_t len); + +int32_t IOS_CheckIOPAddressRange(void *ptr, uint32_t size, MemPermFlags perm); +uint32_t IOS_VirtToPhys(void *ptr); + +int IOS_CreateSemaphore(int32_t maxCount, int32_t initialCount); +int IOS_WaitSemaphore(int id, uint32_t tryWait); +int IOS_SignalSemaphore(int id); +int IOS_DestroySemaphore(int id); #endif diff --git a/source/ios_mcp/source/ipc.c b/source/ios_mcp/source/ipc.c index 0a44d65..9f9e7fe 100644 --- a/source/ios_mcp/source/ipc.c +++ b/source/ios_mcp/source/ipc.c @@ -22,6 +22,7 @@ * distribution. ***************************************************************************/ #include "../../common/kernel_commands.h" +#include "dk.h" #include "fsa.h" #include "imports.h" #include "logger.h" @@ -31,48 +32,50 @@ #include #include -#define IOS_ERROR_UNKNOWN_VALUE 0xFFFFFFD6 -#define IOS_ERROR_INVALID_ARG 0xFFFFFFE3 -#define IOS_ERROR_INVALID_SIZE 0xFFFFFFE9 -#define IOS_ERROR_UNKNOWN 0xFFFFFFF7 -#define IOS_ERROR_NOEXISTS 0xFFFFFFFA +#define IOS_ERROR_UNKNOWN_VALUE 0xFFFFFFD6 +#define IOS_ERROR_INVALID_ARG 0xFFFFFFE3 +#define IOS_ERROR_INVALID_SIZE 0xFFFFFFE9 +#define IOS_ERROR_UNKNOWN 0xFFFFFFF7 +#define IOS_ERROR_NOEXISTS 0xFFFFFFFA -#define IOCTL_MEM_WRITE 0x00 -#define IOCTL_MEM_READ 0x01 -#define IOCTL_SVC 0x02 -#define IOCTL_KILL_SERVER 0x03 -#define IOCTL_MEMCPY 0x04 -#define IOCTL_REPEATED_WRITE 0x05 -#define IOCTL_KERN_READ32 0x06 -#define IOCTL_KERN_WRITE32 0x07 -#define IOCTL_READ_OTP 0x08 +#define IOCTL_MEM_WRITE 0x00 +#define IOCTL_MEM_READ 0x01 +#define IOCTL_SVC 0x02 +#define IOCTL_KILL_SERVER 0x03 +#define IOCTL_MEMCPY 0x04 +#define IOCTL_REPEATED_WRITE 0x05 +#define IOCTL_KERN_READ32 0x06 +#define IOCTL_KERN_WRITE32 0x07 +#define IOCTL_READ_OTP 0x08 -#define IOCTL_FSA_OPEN 0x40 -#define IOCTL_FSA_CLOSE 0x41 -#define IOCTL_FSA_MOUNT 0x42 -#define IOCTL_FSA_UNMOUNT 0x43 -#define IOCTL_FSA_GETDEVICEINFO 0x44 -#define IOCTL_FSA_OPENDIR 0x45 -#define IOCTL_FSA_READDIR 0x46 -#define IOCTL_FSA_CLOSEDIR 0x47 -#define IOCTL_FSA_MAKEDIR 0x48 -#define IOCTL_FSA_OPENFILE 0x49 -#define IOCTL_FSA_READFILE 0x4A -#define IOCTL_FSA_WRITEFILE 0x4B -#define IOCTL_FSA_STATFILE 0x4C -#define IOCTL_FSA_CLOSEFILE 0x4D -#define IOCTL_FSA_SETFILEPOS 0x4E -#define IOCTL_FSA_GETSTAT 0x4F -#define IOCTL_FSA_REMOVE 0x50 -#define IOCTL_FSA_REWINDDIR 0x51 -#define IOCTL_FSA_CHDIR 0x52 -#define IOCTL_FSA_RENAME 0x53 -#define IOCTL_FSA_RAW_OPEN 0x54 -#define IOCTL_FSA_RAW_READ 0x55 -#define IOCTL_FSA_RAW_WRITE 0x56 -#define IOCTL_FSA_RAW_CLOSE 0x57 -#define IOCTL_FSA_CHANGEMODE 0x58 -#define IOCTL_FSA_FLUSHVOLUME 0x59 +#define IOCTL_FSA_OPEN 0x40 +#define IOCTL_FSA_CLOSE 0x41 +#define IOCTL_FSA_MOUNT 0x42 +#define IOCTL_FSA_UNMOUNT 0x43 +#define IOCTL_FSA_GETDEVICEINFO 0x44 +#define IOCTL_FSA_OPENDIR 0x45 +#define IOCTL_FSA_READDIR 0x46 +#define IOCTL_FSA_CLOSEDIR 0x47 +#define IOCTL_FSA_MAKEDIR 0x48 +#define IOCTL_FSA_OPENFILE 0x49 +#define IOCTL_FSA_READFILE 0x4A +#define IOCTL_FSA_WRITEFILE 0x4B +#define IOCTL_FSA_STATFILE 0x4C +#define IOCTL_FSA_CLOSEFILE 0x4D +#define IOCTL_FSA_SETFILEPOS 0x4E +#define IOCTL_FSA_GETSTAT 0x4F +#define IOCTL_FSA_REMOVE 0x50 +#define IOCTL_FSA_REWINDDIR 0x51 +#define IOCTL_FSA_CHDIR 0x52 +#define IOCTL_FSA_RENAME 0x53 +#define IOCTL_FSA_RAW_OPEN 0x54 +#define IOCTL_FSA_RAW_READ 0x55 +#define IOCTL_FSA_RAW_WRITE 0x56 +#define IOCTL_FSA_RAW_CLOSE 0x57 +#define IOCTL_FSA_CHANGEMODE 0x58 +#define IOCTL_FSA_FLUSHVOLUME 0x59 + +#define IOCTLV_DK_PCHAR_ACTIVATE 0x30 static int ipcNodeKilled; static u8 threadStack[0x1000] __attribute__((aligned(0x20))); @@ -384,6 +387,21 @@ static int ipc_ioctl(ipcmessage *message) { return res; } +static int ipc_ioctlv(ipcmessage *message) { + int res = 0; + + switch (message->ioctlv.command) { + case IOCTLV_DK_PCHAR_ACTIVATE: + res = dkPCHARActivateSmd(message->ioctlv.vecs); + break; + default: + res = IOS_ERROR_INVALID_ARG; + break; + } + + return res; +} + static int ipc_thread(void *arg) { int res; ipcmessage *message; @@ -417,7 +435,7 @@ static int ipc_thread(void *arg) { } case IOS_IOCTLV: { log_printf("IOS_IOCTLV\n"); - res = 0; + res = ipc_ioctlv(message); break; } default: { diff --git a/source/ios_mcp/source/ipc_types.h b/source/ios_mcp/source/ipc_types.h index d89fe05..e1a3414 100644 --- a/source/ios_mcp/source/ipc_types.h +++ b/source/ios_mcp/source/ipc_types.h @@ -19,6 +19,11 @@ #define IOS_RESUME 0x0D #define IOS_SVCMSG 0x0E +typedef struct { + void *ptr; + uint32_t len; + uint32_t paddr; +} IOSVec; /* IPC message */ typedef struct ipcmessage { @@ -61,9 +66,9 @@ typedef struct ipcmessage { struct _ioctlv { u32 command; - u32 num_in; - u32 num_io; - struct _ioctlv *vector; + uint32_t num_in; + uint32_t num_out; + IOSVec *vecs; } ioctlv; }; diff --git a/source/ios_mcp/source/main.c b/source/ios_mcp/source/main.c index a4093c6..15e5ebc 100644 --- a/source/ios_mcp/source/main.c +++ b/source/ios_mcp/source/main.c @@ -1,5 +1,4 @@ #include "ipc.h" -#include "wupserver.h" static int threadsStarted = 0; diff --git a/source/ios_mcp/source/mcp_loadfile.c b/source/ios_mcp/source/mcp_loadfile.c index 1ad2ef5..e54b518 100644 --- a/source/ios_mcp/source/mcp_loadfile.c +++ b/source/ios_mcp/source/mcp_loadfile.c @@ -79,9 +79,9 @@ int _MCP_LoadFile_patch(ipcmessage *msg) { if (strncmp(request->name, "men.rpx", strlen("men.rpx")) == 0) { rpxpath[0] = '\0'; if (skipPPCSetup) { - snprintf(rpxpath, sizeof(rpxpath) - 1, "%s/men.rpx", &((char *) 0x05119F00)[19]); // Copy in environment path + snprintf(rpxpath, sizeof(rpxpath) - 1, "%s/men.rpx", &((char *) 0x0511FF00)[19]); // Copy in environment path } else { - snprintf(rpxpath, sizeof(rpxpath) - 1, "%s/root.rpx", &((char *) 0x05119F00)[19]); // Copy in environment path + snprintf(rpxpath, sizeof(rpxpath) - 1, "%s/root.rpx", &((char *) 0x0511FF00)[19]); // Copy in environment path } // At startup we want to hook into the Wii U Menu by replacing the men.rpx with a file from the SD Card @@ -296,7 +296,7 @@ int _MCP_ioctl100_patch(ipcmessage *msg) { } case IPC_CUSTOM_COPY_ENVIRONMENT_PATH: { if (msg->ioctl.buffer_io && msg->ioctl.length_io >= 0x100) { - strncpy((char *) msg->ioctl.buffer_io, (void *) 0x05119F00, 0xFF); + strncpy((char *) msg->ioctl.buffer_io, (void *) 0x0511FF00, 0xFF); return 0; } else { return 29; diff --git a/source/ios_mcp/source/smd.c b/source/ios_mcp/source/smd.c new file mode 100644 index 0000000..4e726be --- /dev/null +++ b/source/ios_mcp/source/smd.c @@ -0,0 +1,320 @@ +#include "smd.h" + +#include +#include + +static SmdIopContext contexts[8]; + +static void *smdPhysToVirt(SmdIopContext *ctx, uint32_t paddr) { + return (void *) (paddr + ctx->memVirtOffset); +} + +static uint32_t smdVirtToPhys(SmdIopContext *ctx, void *vaddr) { + return (uint32_t) vaddr + ctx->memPhysOffset; +} + +int32_t smdIopInit(int32_t index, SmdControlTable *table, const char *name, int lock) { + if (index > 7) { + return -0xc0003; + } + + SmdIopContext *ctx = &contexts[index]; + + // Verify table pointer + if (IOS_CheckIOPAddressRange(table, sizeof(SmdControlTable), MEM_PERM_RW) != 0) { + return -0xc0007; + } + + ctx->controlTable = table; + + if (lock && !ctx->hasSemaphore) { + ctx->semaphore = IOS_CreateSemaphore(1, 1); + if (ctx->semaphore < 0) { + return -0xc0008; + } + + ctx->hasSemaphore = 1; + } + ctx->shouldLock = lock; + + IOS_InvalidateDCache(table, sizeof(SmdControlTable)); + + if (strncmp(table->name, name, sizeof(table->name)) != 0) { + return -0xc0007; + } + + // Calculate virt and phys offsets + uint32_t paddr = IOS_VirtToPhys(table); + ctx->memVirtOffset = (int32_t) table - paddr; + ctx->memPhysOffset = paddr - (int32_t) table; + + ctx->iopElementBuf = (SmdElement *) smdPhysToVirt(ctx, table->iopInterface.bufPaddr); + ctx->iopElementCount = table->iopInterface.elementCount; + + ctx->ppcElementBuf = (SmdElement *) smdPhysToVirt(ctx, table->ppcInterface.bufPaddr); + ctx->ppcElementCount = table->ppcInterface.elementCount; + + // Verify element bufffers + if (IOS_CheckIOPAddressRange(ctx->iopElementBuf, ctx->iopElementCount * sizeof(SmdElement), MEM_PERM_RW) != 0 || + IOS_CheckIOPAddressRange(ctx->ppcElementBuf, ctx->ppcElementCount * sizeof(SmdElement), MEM_PERM_RW) != 0) { + return -0xc0007; + } + + ctx->state = SMD_STATE_INITIALIZED; + return 0; +} + +int32_t smdIopOpen(int32_t index) { + if (index > 7) { + return -0xc0003; + } + + SmdIopContext *ctx = &contexts[index]; + if (ctx->state < SMD_STATE_INITIALIZED) { + return -0xc000d; + } + + // Update interface state + ctx->controlTable->iopInterface.state = SMD_INTERFACE_STATE_OPENED; + IOS_FlushDCache(&ctx->controlTable->iopInterface.state, 4); + + ctx->state = SMD_STATE_OPENED; + return 0; +} + +int32_t smdIopClose(int32_t index) { + if (index > 7) { + return -0xc0003; + } + + SmdIopContext *ctx = &contexts[index]; + if (ctx->state < SMD_STATE_INITIALIZED) { + return -0xc000d; + } + + // Update interface state + ctx->controlTable->iopInterface.state = SMD_INTERFACE_STATE_CLOSED; + IOS_FlushDCache(&ctx->controlTable->iopInterface.state, 4); + + ctx->state = SMD_STATE_CLOSED; + return 0; +} + +int32_t smdIopGetInterfaceState(int32_t index, SmdInterfaceState *iopState, SmdInterfaceState *ppcState) { + if (index > 7) { + return -0xc0003; + } + + SmdIopContext *ctx = &contexts[index]; + if (ctx->state < SMD_STATE_INITIALIZED) { + return -0xc000d; + } + + // Read interface states + if (ppcState) { + IOS_InvalidateDCache(&ctx->controlTable->ppcInterface.state, 4); + *ppcState = (SmdInterfaceState) ctx->controlTable->ppcInterface.state; + } + + if (iopState) { + IOS_InvalidateDCache(&ctx->controlTable->iopInterface.state, 4); + *iopState = (SmdInterfaceState) ctx->controlTable->iopInterface.state; + } + + return 0; +} + +int32_t smdIopReceive(int32_t index, SmdReceiveData *data) { + int32_t ret = 0; + int32_t incoming; + + if (index > 7) { + return -0xc0003; + } + + SmdIopContext *ctx = &contexts[index]; + SmdInterface *iface = &ctx->controlTable->iopInterface; + + memset(data, 0, sizeof(SmdReceiveData)); + + if (ctx->shouldLock) { + IOS_WaitSemaphore(ctx->semaphore, 0); + } + + IOS_InvalidateDCache(iface, sizeof(SmdInterface)); + + if (iface->readOffset > (int32_t) ctx->iopElementCount) { + ret = -0xc0007; + goto done; + } + + // figure out how many incoming elements we can receive + if (iface->readOffset < iface->writeOffset) { + incoming = iface->writeOffset - iface->readOffset; + } else if (iface->writeOffset < iface->readOffset) { + incoming = iface->elementCount - iface->readOffset; + if (iface->writeOffset > 0) { + incoming += iface->writeOffset; + } + } else { + ret = -0xc0005; + goto done; + } + + if (incoming <= 0) { + ret = -0xc0005; + goto done; + } + + SmdElement *element = &ctx->iopElementBuf[iface->readOffset]; + IOS_InvalidateDCache(element, sizeof(SmdElement)); + + data->size = element->size; + data->type = element->type; + + // handle message types + if (element->type == SMD_ELEMENT_TYPE_MESSAGE) { + if (element->size > 0x80) { + ret = -0xc0001; + goto done; + } + + memcpy(data->message, element->data, element->size); + } else if (element->type == SMD_ELEMENT_TYPE_VECTOR_SPEC) { + SmdVector *vec = &element->spec; + data->spec.count = vec->count; + data->spec.id = vec->id; + + if (data->spec.count > 4) { + ret = -0xc0002; + goto done; + } + + // Translate and verify spec pointers + for (int i = 0; i < data->spec.count; ++i) { + SmdVectorSpec *spec = &data->spec.vecs[i]; + spec->ptr = smdPhysToVirt(ctx, (uint32_t) vec->vecs[i].ptr); + spec->size = vec->vecs[i].size; + + if (IOS_CheckIOPAddressRange(spec->ptr, spec->size, MEM_PERM_RW) != 0) { + ret = -0xc000f; + goto done; + } + + IOS_InvalidateDCache(spec->ptr, spec->size); + } + } else if (element->type == SMD_ELEMENT_TYPE_VECTOR) { + SmdVector *vec = (SmdVector *) smdPhysToVirt(ctx, element->vectorPaddr); + IOS_InvalidateDCache(vec, sizeof(SmdVector)); + + if (vec->count > 4) { + ret = -0xc0002; + goto done; + } + + data->vector = vec; + + // Translate and verify pointers + for (int i = 0; i < vec->count; ++i) { + SmdVectorSpec *spec = &data->vector->vecs[i]; + spec->ptr = smdPhysToVirt(ctx, (uint32_t) spec->ptr); + + if (IOS_CheckIOPAddressRange(spec->ptr, spec->size, MEM_PERM_RW) != 0) { + ret = -0xc000f; + goto done; + } + + IOS_InvalidateDCache(spec->ptr, spec->size); + } + } else { + ret = -0xc0006; + goto done; + } + + // Increment read offset + iface->readOffset = (iface->readOffset + 1) % iface->elementCount; + IOS_FlushDCache(&iface->readOffset, 4); + +done:; + if (ctx->shouldLock) { + IOS_SignalSemaphore(ctx->semaphore); + } + + return ret; +} + +static int32_t writeElement(SmdIopContext *ctx, SmdElementType type, void *data, uint32_t size) { + int32_t ret = 0; + int32_t outgoing; + + if (ctx->shouldLock) { + IOS_WaitSemaphore(ctx->semaphore, 0); + } + + SmdInterface *iface = &ctx->controlTable->ppcInterface; + IOS_InvalidateDCache(iface, sizeof(SmdInterface)); + + if (iface->writeOffset > (int32_t) ctx->ppcElementCount) { + ret = -0xc0007; + goto done; + } + + // figure out how many outgoing messages we can send + if (iface->writeOffset < iface->readOffset) { + outgoing = iface->readOffset - iface->writeOffset; + } else { + outgoing = iface->elementCount - iface->writeOffset; + if (iface->readOffset >= 0) { + outgoing += iface->readOffset; + } + } + + if (outgoing <= 0) { + goto done; + } + + // write data to element + SmdElement *element = &ctx->ppcElementBuf[iface->writeOffset]; + element->type = type; + element->size = size; + memcpy(element->data, data, size); + + IOS_FlushDCache(element, sizeof(SmdElement)); + + // Increment write offset + iface->writeOffset = (iface->writeOffset + 1) % iface->elementCount; + IOS_FlushDCache(&iface->writeOffset, 4); + +done:; + if (ctx->shouldLock) { + IOS_SignalSemaphore(ctx->semaphore); + } + + return ret; +} + +int32_t smdIopSendVector(int32_t index, SmdVector *vector) { + if (index > 7) { + return -0xc0003; + } + + SmdIopContext *ctx = &contexts[index]; + + if (vector->count > 4) { + return -0xc0002; + } + + // flush and translate pointers + for (int i = 0; i < vector->count; ++i) { + SmdVectorSpec *spec = &vector->vecs[i]; + IOS_FlushDCache(spec->ptr, spec->size); + + spec->ptr = (void *) smdVirtToPhys(ctx, spec->ptr); + } + + IOS_FlushDCache(vector, sizeof(SmdVector)); + + // write vector paddr as element + uint32_t paddr = smdVirtToPhys(ctx, vector); + return writeElement(ctx, SMD_ELEMENT_TYPE_VECTOR, &paddr, sizeof(paddr)); +} diff --git a/source/ios_mcp/source/smd.h b/source/ios_mcp/source/smd.h new file mode 100644 index 0000000..2dd9d95 --- /dev/null +++ b/source/ios_mcp/source/smd.h @@ -0,0 +1,128 @@ +#pragma once + +#include +#include + +#ifndef PACKED +#define PACKED __attribute__((__packed__)) +#endif + +#ifndef CHECK_SIZE +#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, #type " must be " #size " bytes") +#endif + +typedef enum SmdState SmdState; +typedef enum SmdInterfaceState SmdInterfaceState; +typedef enum SmdElementType SmdElementType; +typedef struct SmdIopContext SmdIopContext; +typedef struct SmdInterface SmdInterface; +typedef struct SmdControlTable SmdControlTable; +typedef struct SmdVectorSpec SmdVectorSpec; +typedef struct SmdVector SmdVector; +typedef struct SmdElement SmdElement; +typedef struct SmdReceiveData SmdReceiveData; + +enum SmdState { + SMD_STATE_INVALID = 0, + SMD_STATE_INITIALIZED = 2, + SMD_STATE_CLOSED = 3, + SMD_STATE_OPENED = 4, +}; + +enum SmdInterfaceState { + SMD_INTERFACE_STATE_OPENED = 0x2222, + SMD_INTERFACE_STATE_CLOSED = 0x3333, +}; + +enum SmdElementType { + SMD_ELEMENT_TYPE_MESSAGE = 0, + SMD_ELEMENT_TYPE_VECTOR_SPEC = 1, + SMD_ELEMENT_TYPE_VECTOR = 2, +}; + +struct SmdIopContext { + SmdControlTable *controlTable; + int32_t memVirtOffset; + int32_t memPhysOffset; + int shouldLock; + int semaphore; + int hasSemaphore; + int logHandle; + SmdElement *iopElementBuf; + uint32_t iopElementCount; + SmdElement *ppcElementBuf; + uint32_t ppcElementCount; + SmdState state; +}; + +struct PACKED SmdInterface { + uint32_t state; + uint8_t __padding0[0x7C]; + uint32_t elementCount; + uint8_t __padding1[0x7C]; + int32_t readOffset; + uint8_t __padding2[0x7C]; + int32_t writeOffset; + uint8_t __padding3[0x7C]; + uint32_t bufPaddr; + uint8_t __padding4[0x7C]; +}; +CHECK_SIZE(SmdInterface, 0x280); + +struct PACKED SmdControlTable { + char name[0x10]; + uint32_t reinitCount; + uint8_t __padding0[0x6C]; + SmdInterface iopInterface; + uint8_t __padding1[0x40]; + SmdInterface ppcInterface; + uint8_t __padding2[0x40]; +}; +CHECK_SIZE(SmdControlTable, 0x600); + +struct PACKED SmdVectorSpec { + void *ptr; + uint32_t size; +}; +CHECK_SIZE(SmdVectorSpec, 0x8); + +struct PACKED SmdVector { + uint32_t id; + int32_t count; + SmdVectorSpec vecs[4]; +}; +CHECK_SIZE(SmdVector, 0x28); + +struct PACKED SmdElement { + uint32_t type; + uint32_t size; + union { + uint8_t data[0xf8]; + SmdVector spec; + uint32_t vectorPaddr; + }; +}; +CHECK_SIZE(SmdElement, 0x100); + +struct PACKED SmdReceiveData { + uint32_t type; + uint32_t size; + union { + uint8_t message[0x80]; + SmdVector spec; + SmdVector *vector; + }; +}; +CHECK_SIZE(SmdReceiveData, 0x88); + +int32_t smdIopInit(int32_t index, SmdControlTable *table, const char *name, int lock); + +int32_t smdIopOpen(int32_t index); + +int32_t smdIopClose(int32_t index); + +int32_t smdIopGetInterfaceState(int32_t index, SmdInterfaceState *iopState, SmdInterfaceState *ppcState); + +int32_t smdIopReceive(int32_t index, SmdReceiveData *data); + +int32_t smdIopSendVector(int32_t index, SmdVector *vector); diff --git a/source/ios_mcp/source/socket.c b/source/ios_mcp/source/socket.c index 15ed892..31125c7 100644 --- a/source/ios_mcp/source/socket.c +++ b/source/ios_mcp/source/socket.c @@ -209,3 +209,27 @@ int send(int sockfd, const void *buf, size_t len, int flags) { freeIobuf(iobuf); return ret; } + +int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) { + void *data_buf = svcAllocAlign(0xCAFF, optlen, 0x40); + if (!data_buf) return -100; + + u8 *iobuf = allocIobuf(sizeof(IOSVec) * 2 + sizeof(uint32_t) * 3); + iovec_s *iovec = (iovec_s *) iobuf; + + memcpy(data_buf, optval, optlen); + iovec[0].ptr = data_buf; + iovec[0].len = optlen; + + iovec[1].ptr = iovec; + iovec[1].len = sizeof(IOSVec) * 3; + + ((uint32_t *) iovec)[6] = sockfd; + ((uint32_t *) iovec)[7] = level; + ((uint32_t *) iovec)[8] = optname; + + int ret = svcIoctlv(socket_handle, 0x9, 2, 0, iovec); + freeIobuf(iobuf); + freeIobuf(data_buf); + return ret; +} diff --git a/source/ios_mcp/source/socket.h b/source/ios_mcp/source/socket.h index 0178988..e67d397 100644 --- a/source/ios_mcp/source/socket.h +++ b/source/ios_mcp/source/socket.h @@ -5,7 +5,7 @@ #include #include -#define SOL_SOCKET 0xFFFF +#define SOL_SOCKET -1 #define PF_UNSPEC 0 #define PF_INET 2 @@ -30,24 +30,29 @@ #define SHUT_WR 1 #define SHUT_RDWR 2 -#define SO_DEBUG 0x0001 -#define SO_ACCEPTCONN 0x0002 -#define SO_REUSEADDR 0x0004 -#define SO_KEEPALIVE 0x0008 -#define SO_DONTROUTE 0x0010 -#define SO_BROADCAST 0x0020 -#define SO_USELOOPBACK 0x0040 -#define SO_LINGER 0x0080 -#define SO_OOBINLINE 0x0100 -#define SO_REUSEPORT 0x0200 -#define SO_SNDBUF 0x1001 -#define SO_RCVBUF 0x1002 -#define SO_SNDLOWAT 0x1003 -#define SO_RCVLOWAT 0x1004 -#define SO_SNDTIMEO 0x1005 -#define SO_RCVTIMEO 0x1006 -#define SO_ERROR 0x1007 -#define SO_TYPE 0x1008 +/* + * SOL_SOCKET options + */ +#define SO_REUSEADDR 0x0004 // reuse address +#define SO_KEEPALIVE 0x0008 // keep connections alive +#define SO_BROADCAST 0x0020 // broadcast +#define SO_LINGER 0x0080 // linger (no effect?) +#define SO_OOBINLINE 0x0100 // out-of-band data inline (no effect?) +#define SO_TCPSACK 0x0200 // set tcp selective acknowledgment +#define SO_WINSCALE 0x0400 // set tcp window scaling +#define SO_SNDBUF 0x1001 // send buffer size +#define SO_RCVBUF 0x1002 // receive buffer size +#define SO_SNDLOWAT 0x1003 // send low-water mark (no effect?) +#define SO_RCVLOWAT 0x1004 // receive low-water mark +#define SO_TYPE 0x1008 // get socket type +#define SO_ERROR 0x1009 // get socket error +#define SO_RXDATA 0x1011 // get count of bytes in sb_rcv +#define SO_TXDATA 0x1012 // get count of bytes in sb_snd +#define SO_NBIO 0x1014 // set socket to NON-blocking mode +#define SO_BIO 0x1015 // set socket to blocking mode +#define SO_NONBLOCK 0x1016 // set/get blocking mode via optval param + +#define TCP_NODELAY 0x2004 #define INADDR_ANY 0x00000000 #define INADDR_BROADCAST 0xFFFFFFFF