From 4d78f128719fe712aa6a714a781c545b88e64957 Mon Sep 17 00:00:00 2001 From: TuxSH Date: Tue, 23 Jan 2018 07:34:38 +0100 Subject: [PATCH] Implement most bsd:u/s service commands --- nx/include/switch/services/bsd.h | 62 +-- nx/source/services/bsd.c | 864 ++++++++++++++++++++----------- 2 files changed, 598 insertions(+), 328 deletions(-) diff --git a/nx/include/switch/services/bsd.h b/nx/include/switch/services/bsd.h index 8191aa6f..189e140e 100644 --- a/nx/include/switch/services/bsd.h +++ b/nx/include/switch/services/bsd.h @@ -22,42 +22,42 @@ typedef struct { u32 udp_rx_buf_size; ///< Size of the UDP receive buffer (typically 0xA500 bytes). u32 sb_efficiency; ///< Number of buffers for each socket (standard values range from 1 to 8). -} BsdConfig; +} BsdBufferConfig; -struct bsd_sockaddr_in { - u8 sin_len; - u8 sin_family; - u16 sin_port; - u32 sin_addr; - u8 sin_zero[8]; -}; - -const BsdConfig *bsdGetDefaultConfig(void); -Result bsdInitialize(const BsdConfig *config); +const BsdBufferConfig *bsdGetDefaultBufferConfig(void); +Result bsdInitialize(const BsdBufferConfig *config); void bsdExit(void); -int bsdGetErrno(void); -int bsdConnect(int sockfd, const void* addr, u32 addrlen); + int bsdSocket(int domain, int type, int protocol); -int bsdBind(int sockfd, const void* addr, u32 addrlen); +int bsdSocketExempt(int domain, int type, int protocol); +int bsdOpen(const char *pathname, int flags); +int bsdSelect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); +int bsdPoll(struct pollfd *fds, nfds_t nfds, int timeout); +int bsdSysctl(const int *name, size_t namelen, void *oldp, size_t *oldlenp, const void *newp, size_t newlen); +ssize_t bsdRecv(int sockfd, void *buf, size_t len, int flags); +ssize_t bsdRecvFrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); +int bsdSend(int sockfd, const void* buf, size_t len, int flags); +int bsdSendTo(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); +int bsdAccept(int sockfd, struct sockaddr *address, socklen_t *addrlen); +int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int bsdConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int bsdGetPeerName(int sockfd, struct sockaddr *address, socklen_t *addrlen); +int bsdGetSockName(int sockfd, struct sockaddr *address, socklen_t *addrlen); +int bsdGetSockOpt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); int bsdListen(int sockfd, int backlog); -int bsdSend(int sockfd, const void* buffer, size_t length, int flags); -int bsdSendTo(int sockfd, const void* buffer, size_t length, int flags, const struct bsd_sockaddr_in *dest_addr, size_t dest_len); -int bsdRecv(int sockfd, void* buffer, size_t length, int flags); -int bsdSetSockOpt(int sockfd, int level, int option_name, const void *option_value, size_t option_size); -int bsdWrite(int sockfd, const void* buffer, size_t length); +int bsdIoctl(int fd, int request, ...); +int bsdFnctl(int fd, int cmd, ...); +int bsdSetSockOpt(int sockfd, int level, int optname, const void *optval, size_t optlen); +int bsdShutdown(int sockfd, int how); +int bsdShutdownAllSockets(int how); +ssize_t bsdWrite(int fd, const void *buf, size_t count); +ssize_t bsdRead(int fd, void *buf, size_t count); +int bsdClose(int fd); +int bsdDuplicateSocket(int sockfd); + +//TODO: Reverse-engineer GetResourceStatistics, sendmmsg/recvmmsg (custom (un)serialization) static inline Result bsdInitializeDefault(void) { - return bsdInitialize(bsdGetDefaultConfig()); + return bsdInitialize(bsdGetDefaultBufferConfig()); } - -#define BSD_AF_INET 2 -#define BSD_AF_INET6 10 -#define BSD_IPPROTO_IP 0 -#define BSD_IPPROTO_TCP 6 -#define BSD_IPPROTO_UDP 17 - -#define BSD_SOCK_STREAM 1 -#define BSD_SOCK_DGRAM 2 - -#define BSD_MSG_RECV_ALL 0x40 diff --git a/nx/source/services/bsd.c b/nx/source/services/bsd.c index b0cfbd6f..b5f0d69c 100644 --- a/nx/source/services/bsd.c +++ b/nx/source/services/bsd.c @@ -1,4 +1,6 @@ // Copyright 2017 plutoo +#include + #include "types.h" #include "result.h" #include "ipc.h" @@ -12,11 +14,10 @@ static Service g_bsdSrv; static Service g_bsdMonitor; static u64 g_bsdClientPid = -1; -static int g_Errno = 0; static TransferMemory g_bsdTmem; -static const BsdConfig g_defaultBsdConfig = { +static const BsdBufferConfig g_defaultBsdBufferConfig = { .version = 1, .tcp_tx_buf_size = 0x8000, @@ -35,7 +36,7 @@ static const BsdConfig g_defaultBsdConfig = { Should the transfer memory be smaller than that, the BSD sockets service would only send ZeroWindow packets (for TCP), resulting in a transfer rate not exceeding 1 byte/s. */ -static size_t _bsdGetTransferMemSizeForConfig(const BsdConfig *config) +static size_t _bsdGetTransferMemSizeForConfig(const BsdBufferConfig *config) { u32 tcp_tx_buf_max_size = config->tcp_tx_buf_max_size != 0 ? config->tcp_tx_buf_max_size : config->tcp_tx_buf_size; u32 tcp_rx_buf_max_size = config->tcp_rx_buf_max_size != 0 ? config->tcp_rx_buf_max_size : config->tcp_rx_buf_size; @@ -45,7 +46,7 @@ static size_t _bsdGetTransferMemSizeForConfig(const BsdConfig *config) return (size_t)(config->sb_efficiency * sum); } -static Result _bsdRegisterClient(Service* srv, TransferMemory* tmem, const BsdConfig *config, u64* pid_out) { +static Result _bsdRegisterClient(Service* srv, TransferMemory* tmem, const BsdBufferConfig *config, u64* pid_out) { IpcCommand c; ipcInitialize(&c); ipcSendPid(&c); @@ -57,7 +58,6 @@ static Result _bsdRegisterClient(Service* srv, TransferMemory* tmem, const BsdCo BsdConfig config; u64 pid_reserved; u64 tmem_sz; - u64 pad[2]; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); @@ -121,11 +121,107 @@ static Result _bsdStartMonitor(Service* srv, u64 pid) { return rc; } -const BsdConfig *bsdGetDefaultConfig(void) { +typedef struct { + u64 magic; + u64 result; + int ret; + int errno_; +} BsdIpcResponseBase; + +static int _bsdDispatchBasicCommand(IpcCommand *c, IpcParsedCommand *rOut) { + Result rc = serviceIpcDispatch(&g_bsdSrv); + IpcParsedCommand r; + int ret = -1; + + if (R_SUCCEEDED(rc)) { + ipcParse(&r); + + BsdIpcResponseBase *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + errno = resp->errno_; + ret = resp->ret; + } + } + + if (R_FAILED(rc)) + errno = EPIPE; + + if(rOut != NULL) + *rOut = r; + + return ret; +} + +static int _bsdDispatchCommandWithOutAddrlen(IpcCommand *c, socklen_t *addrlen) +{ + IpcParsedCommand r; + int ret = _bsdDispatchBasicCommand(&c, &r); + if(ret != -1 && *addrlen != NULL) + { + struct { + BsdIpcResponseBase bsd_resp; + socklen_t addrlen; + } *resp = r.Raw; + *addrlen = resp->addrlen; + } + return ret; +} + +static int _bsdNameGetterCommand(u32 cmd_id, int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + IpcCommand c; + ipcInitialize(&c); + + socklen_t maxaddrlen = addrlen == NULL ? 0 : *addrlen; + + ipcAddRecvBuffer(&c, addr, maxaddrlen, 0); + ipcAddRecvStatic(&c, addr, maxaddrlen, 0); + + struct { + u64 magic; + u64 cmd_id; + int sockfd; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + raw->sockfd = sockfd; + + return _bsdDispatchCommandWithOutAddrlen(&c, addrlen); +} + +static int _bsdSocketCreationCommand(u32 cmd_id, int domain, int type, int protocol) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + int domain; + int type; + int protocol; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = cmd_id; + raw->domain = domain; + raw->type = type; + raw->protocol = protocol; + + return _bsdDispatchBasicCommand(&c, NULL); +} + +const BsdConfig *bsdGetDefaultBufferConfig(void) { return &g_defaultBsdConfig; } -Result bsdInitialize(const BsdConfig *config) { +Result bsdInitialize(const BsdBufferConfig *config) { const char* bsd_srv = "bsd:s"; if(serviceIsActive(&g_bsdSrv) || serviceIsActive(&g_bsdMonitor)) @@ -164,70 +260,137 @@ void bsdExit(void) { tmemClose(&g_bsdTmem); } -int bsdGetErrno(void) { - return g_Errno; +int bsdSocket(int domain, int type, int protocol) { + return _bsdSocketCreationCommand(2, domain, type, protocol); } -int bsdSocket(int domain, int type, int protocol) { +int bsdSocketExempt(int domain, int type, int protocol) { + return _bsdSocketCreationCommand(3, domain, type, protocol); +} + +int bsdOpen(const char *pathname, int flags) { IpcCommand c; ipcInitialize(&c); + size_t pathlen = strnlen(pathname, 256); + ipcAddSendBuffer(&c, pathname, flags, 0); + ipcAddSendStatic(&c, pathname, flags, 0); + struct { u64 magic; u64 cmd_id; - u32 domain; - u32 type; - u32 protocol; - u32 pad[4]; + int flags; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; - raw->cmd_id = 2; - raw->domain = domain; - raw->type = type; - raw->protocol = protocol; + raw->cmd_id = 4; + raw->flags = flags; - Result rc = serviceIpcDispatch(&g_bsdSrv); - int fd = -1; - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 fd; - u32 errno; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - g_Errno = resp->errno; - fd = resp->fd; - } - } - - if (R_FAILED(rc)) { - g_Errno = EPIPE; - } - - return fd; + return _bsdDispatchBasicCommand(&c, NULL); } -int bsdRecv(int sockfd, void* buffer, size_t length, int flags) { + +int bsdSelect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { IpcCommand c; ipcInitialize(&c); - ipcAddRecvBuffer(&c, buffer, length, 0); - ipcAddRecvStatic(&c, buffer, length, 0); + + ipcAddSendBuffer(&c, readfds, sizeof(fd_set), 0); + ipcAddSendStatic(&c, readfds, sizeof(fd_set), 0); + ipcAddSendBuffer(&c, writefds, sizeof(fd_set), 0); + ipcAddSendStatic(&c, writefds, sizeof(fd_set), 0); + ipcAddSendBuffer(&c, exceptfds, sizeof(fd_set), 0); + ipcAddSendStatic(&c, exceptfds, sizeof(fd_set), 0); + + ipcAddRecvBuffer(&c, readfds, sizeof(fd_set), 0); + ipcAddRecvStatic(&c, readfds, sizeof(fd_set), 0); + ipcAddRecvBuffer(&c, writefds, sizeof(fd_set), 0); + ipcAddRecvStatic(&c, writefds, sizeof(fd_set), 0); + ipcAddRecvBuffer(&c, exceptfds, sizeof(fd_set), 0); + ipcAddRecvStatic(&c, exceptfds, sizeof(fd_set), 0); struct { u64 magic; u64 cmd_id; - u32 sockfd; - u32 flags; + int nfds; + struct timeout timeout; + bool nullTimeout; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 5; + raw->nfds = nfds; + if(!(raw->nullTimeout = timeout == NULL)) + raw->timeout = *timeout; + + return _bsdDispatchBasicCommand(&c, NULL); +} + +int bsdPoll(struct pollfd *fds, nfds_t nfds, int timeout) { + IpcCommand c; + ipcInitialize(&c); + + ipcAddSendBuffer(&c, fds, sizeof(struct pollfd), 0); + ipcAddSendStatic(&c, fds, sizeof(struct pollfd), 0); + + ipcAddRecvBuffer(&c, fds, sizeof(struct pollfd), 0); + ipcAddRecvStatic(&c, fds, sizeof(struct pollfd), 0); + + struct { + u64 magic; + u64 cmd_id; + nfds_t nfds; + int timeout; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 6; + raw->nfds = nfds; + raw->timeout = timeout; + + return _bsdDispatchBasicCommand(&c, NULL); +} + +int bsdSysctl(const int *name, unsigned int namelen, void *oldp, size_t *oldlenp, const void *newp, size_t newlen) { + IpcCommand c; + ipcInitialize(&c); + + ipcAddSendBuffer(&c, name, 4 * namelen, 0); + ipcAddSendStatic(&c, name, 4 * namelen, 0); + ipcAddSendBuffer(&c, newp, newlen, 0); + ipcAddSendStatic(&c, newp, newlen, 0); + + ipcAddRecvBuffer(&c, oldp, oldlenp, 0); + ipcAddRecvStatic(&c, oldp, oldlenp, 0); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 7; + + return _bsdDispatchBasicCommand(&c, NULL); +} + +ssize_t bsdRecv(int sockfd, void *buf, size_t len, int flags) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buf, len, 0); + ipcAddRecvStatic(&c, buf, len, 0); + + struct { + u64 magic; + u64 cmd_id; + int sockfd; + int flags; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); @@ -237,46 +400,48 @@ int bsdRecv(int sockfd, void* buffer, size_t length, int flags) { raw->sockfd = sockfd; raw->flags = flags; - Result rc = serviceIpcDispatch(&g_bsdSrv); - int ret = -1; - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 ret; - u32 errno; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - g_Errno = resp->errno; - ret = resp->ret; - } - } - - if (R_FAILED(rc)) { - g_Errno = rc; //EPIPE; - } - - return ret; + return _bsdDispatchBasicCommand(&c, NULL); } -int bsdSend(int sockfd, const void* buffer, size_t length, int flags) { +ssize_t bsdRecvFrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen){ IpcCommand c; + socklen_t inaddrlen = addrlen == NULL ? 0 : *addrlen; + ipcInitialize(&c); - ipcAddSendBuffer(&c, buffer, length, 0); - ipcAddSendStatic(&c, buffer, length, 0); + + ipcAddRecvBuffer(&c, buf, len, 0); + ipcAddRecvStatic(&c, buf, len, 0); + ipcAddRecvBuffer(&c, src_addr, inaddrlen, 0); + ipcAddRecvBuffer(&c, src_addr, inaddrlen, 0); struct { u64 magic; u64 cmd_id; - u32 sockfd; - u32 flags; + int sockfd; + int flags; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 9; + raw->sockfd = sockfd; + raw->flags = flags; + + return _bsdDispatchCommandWithOutAddrlen(&c, addrlen); +} + +int bsdSend(int sockfd, const void* buf, size_t len, int flags) { + IpcCommand c; + ipcInitialize(&c); + ipcAddSendBuffer(&c, buf, len, 0); + ipcAddSendStatic(&c, buf, len, 0); + + struct { + u64 magic; + u64 cmd_id; + int sockfd; + int flags; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); @@ -286,49 +451,23 @@ int bsdSend(int sockfd, const void* buffer, size_t length, int flags) { raw->sockfd = sockfd; raw->flags = flags; - Result rc = serviceIpcDispatch(&g_bsdSrv); - int ret = -1; - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 ret; - u32 errno; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - g_Errno = resp->errno; - ret = resp->ret; - } - } - - if (R_FAILED(rc)) { - g_Errno = EPIPE; - } - - return ret; + return _bsdDispatchBasicCommand(&c, NULL); } -int bsdSendTo(int sockfd, const void* buffer, size_t length, int flags, const struct bsd_sockaddr_in *dest_addr, size_t dest_len) { +int bsdSendTo(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) { IpcCommand c; ipcInitialize(&c); - ipcAddSendBuffer(&c, buffer, length, 0); - ipcAddSendStatic(&c, buffer, length, 0); + ipcAddSendBuffer(&c, buffer, len, 0); + ipcAddSendStatic(&c, buffer, len, 0); - ipcAddSendBuffer(&c, dest_addr, dest_len, 0); - ipcAddSendStatic(&c, dest_addr, dest_len, 0); + ipcAddSendBuffer(&c, dest_addr, addrlen, 1); + ipcAddSendStatic(&c, dest_addr, addrlen, 1); struct { u64 magic; u64 cmd_id; - u32 sockfd; - u32 flags; + int sockfd; + int flags; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); @@ -338,36 +477,14 @@ int bsdSendTo(int sockfd, const void* buffer, size_t length, int flags, const st raw->sockfd = sockfd; raw->flags = flags; - Result rc = serviceIpcDispatch(&g_bsdSrv); - int ret = -1; - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 ret; - u32 errno; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - g_Errno = resp->errno; - ret = resp->ret; - } - } - - if (R_FAILED(rc)) { - g_Errno = EPIPE; - } - - return ret; + return _bsdDispatchBasicCommand(&c, NULL); } -int bsdConnect(int sockfd, const void* addr, u32 addrlen) { +int bsdAccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + return _bsdNameGetterCommand(12, sockfd, addr, addrlen); +} + +int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { IpcCommand c; ipcInitialize(&c); ipcAddSendBuffer(&c, addr, addrlen, 0); @@ -376,8 +493,26 @@ int bsdConnect(int sockfd, const void* addr, u32 addrlen) { struct { u64 magic; u64 cmd_id; - u32 sockfd; - u32 pad[4]; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 13; + + return _bsdDispatchBasicCommand(&c, NULL); +} + +int bsdConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { + IpcCommand c; + ipcInitialize(&c); + ipcAddSendBuffer(&c, addr, addrlen, 0); + ipcAddSendStatic(&c, addr, addrlen, 0); + + struct { + u64 magic; + u64 cmd_id; + int sockfd; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); @@ -386,79 +521,43 @@ int bsdConnect(int sockfd, const void* addr, u32 addrlen) { raw->cmd_id = 14; raw->sockfd = sockfd; - Result rc = serviceIpcDispatch(&g_bsdSrv); - int fd = -1; - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 fd; - u32 errno; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - g_Errno = resp->errno; - fd = resp->fd; - } - } - - if (R_FAILED(rc)) { - g_Errno = EPIPE; - } - - return fd; + return _bsdDispatchBasicCommand(&c, NULL); } -int bsdBind(int sockfd, const void* addr, u32 addrlen) { +int bsdGetPeerName(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + return _bsdNameGetterCommand(15, sockfd, addr, addrlen); +} + +int bsdGetSockName(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { + return _bsdNameGetterCommand(16, sockfd, addr, addrlen); +} + +int bsdGetSockOpt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) { IpcCommand c; ipcInitialize(&c); - ipcAddSendBuffer(&c, addr, addrlen, 0); - ipcAddSendStatic(&c, addr, addrlen, 0); + + socklen_t inoptlen = optlen == NULL ? 0 : *optlen; + + ipcAddRecvBuffer(&c, optval, inoptlen, 0); + ipcAddRecvStatic(&c, optval, inoptlen, 0); struct { u64 magic; u64 cmd_id; - u32 pad[5]; + int sockfd; + int level; + int optname; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; - raw->cmd_id = 13; + raw->cmd_id = 17; + raw->sockfd = sockfd; + raw->level = level; + raw->optname = optname; - Result rc = serviceIpcDispatch(&g_bsdSrv); - int ret = -1; - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 ret; - u32 errno; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - g_Errno = resp->errno; - ret = resp->ret; - } - } - - if (R_FAILED(rc)) { - g_Errno = EPIPE; - } - - return ret; + return _bsdDispatchBasicCommand(&c, NULL); } int bsdListen(int sockfd, int backlog) { @@ -468,9 +567,8 @@ int bsdListen(int sockfd, int backlog) { struct { u64 magic; u64 cmd_id; - u32 sockfd; - u32 backlog; - u32 pad[4]; + int sockfd; + int backlog; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); @@ -480,48 +578,171 @@ int bsdListen(int sockfd, int backlog) { raw->sockfd = sockfd; raw->backlog = backlog; - Result rc = serviceIpcDispatch(&g_bsdSrv); - int ret = -1; + return _bsdDispatchBasicCommand(&c, NULL); +} - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); +// Not in bsd.h, exposed for the newlib compatibility wrapper +int bsdIoctl_v(int fd, int request, va_list args) { + IpcCommand c; - struct { - u64 magic; - u64 result; - u32 ret; - u32 errno; - } *resp = r.Raw; + const void *data = NULL, in2 = NULL, in3 = NULL, in4 = NULL; + size_t in1sz = 0, in2sz = 0, in3sz = 0; - rc = resp->result; + const void *out1 = NULL, out2 = NULL, out3 = NULL, out4 = NULL; + size_t out1sz = 0, out2sz = 0, out3sz = 0; - if (R_SUCCEEDED(rc)) { - g_Errno = resp->errno; - ret = resp->ret; + int bufcount = 1; + + switch(request) { + case SIOCGIFCONF: + { + struct ifconf *data = va_arg(args, struct ifconf *); + in1 = out1 = data; + in1sz = out1sz = sizeof(struct ifconf); + in2 = out2 = data->ifc_req; + in2sz = out2sz = data->ifc_len; + bufcount = 2; + break; + } + case SIOCGIFMEDIA: + case SIOCGIFXMEDIA: + { + struct ifmediareq *data = va_arg(args, struct ifmediareq *); + in1 = out1 = data; + in1sz = out1sz = sizeof(struct ifmediareq); + in2 = out2 = data->ifm_ulist; + in2sz = out2sz = 8 * data->ifm_count; + bufcount = 2; + break; + } + // Generic ioctl + default: + { + void *data = NULL; + if(request & IOC_INOUT) + data = va_arg(args, void *); + if(request & IOC_IN) + { + in1 = data; + in1sz = IOCPARM_LEN(request); + } + if(request & IOC_OUT) + { + out1 = data; + out1sz = IOCPARM_LEN(request); + } + break; } } - if (R_FAILED(rc)) { - g_Errno = EPIPE; - } - - return ret; -} - -int bsdSetSockOpt(int sockfd, int level, int option_name, const void *option_value, size_t option_size) { - IpcCommand c; ipcInitialize(&c); - ipcAddSendBuffer(&c, option_value, option_size, 0); - ipcAddSendStatic(&c, option_value, option_size, 0); + ipcAddSendBuffer(&c, in1, in1sz, 0); + ipcAddSendStatic(&c, in1, in1sz, 0); + ipcAddSendBuffer(&c, in2, in2sz, 0); + ipcAddSendStatic(&c, in2, in2sz, 0); + ipcAddSendBuffer(&c, in3, in3sz, 0); + ipcAddSendStatic(&c, in3, in3sz, 0); + ipcAddSendBuffer(&c, in4, in4sz, 0); + ipcAddSendStatic(&c, in4, in4sz, 0); + + ipcAddRecvBuffer(&c, out1, out1sz, 0); + ipcAddRecvStatic(&c, out1, out1sz, 0); + ipcAddRecvBuffer(&c, out2, out2sz, 0); + ipcAddRecvStatic(&c, out2, out2sz, 0); + ipcAddRecvBuffer(&c, out3, out3sz, 0); + ipcAddRecvStatic(&c, out3, out3sz, 0); + ipcAddRecvBuffer(&c, out4, out4sz, 0); + ipcAddRecvStatic(&c, out4, out4sz, 0); struct { u64 magic; u64 cmd_id; - u32 sockfd; - u32 level; - u32 option_name; + int fd; + int request; + int bufcount; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 19; + raw->fd = fd; + raw->request = request; + raw->bufcount = bufcount; + + return _bsdDispatchBasicCommand(&c, NULL); +} + +int bsdIoctl(int fd, int request, ...) { + int ret; + + va_list args; + va_start(args, request); + ret = bsdIoctl_v(fd, request, args); + va_end(args); + + return ret; +} + +// Not in bsd.h, exposed for the newlib compatibility wrapper +int bsdFnctl_v(int fd, int cmd, va_list args) { + IpcCommand c; + int arg = 0; + + if(cmd == F_GETFL || cmd == F_SETFL) { + errno = 0; + return -1; + } + + if(cmd == F_SETFL) + arg = va_arg(args, int); + + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + int fd; + int cmd; + int arg; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 20; + raw->fd = fd; + raw->cmd = cmd; + raw->arg = arg; + + return _bsdDispatchBasicCommand(&c, NULL); +} + +int bsdFnctl(int fd, int cmd, ...) { + int ret; + + va_list args; + va_start(args, cmd); + ret = bsdFnctl_v(fd, cmd, args); + va_end(args); + + return ret; +} + +int bsdSetSockOpt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) { + IpcCommand c; + ipcInitialize(&c); + + ipcAddSendBuffer(&c, optval, optlen, 0); + ipcAddSendStatic(&c, optval, optlen, 0); + + struct { + u64 magic; + u64 cmd_id; + int sockfd; + int level; + int optname; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); @@ -530,80 +751,129 @@ int bsdSetSockOpt(int sockfd, int level, int option_name, const void *option_val raw->cmd_id = 21; raw->sockfd = sockfd; raw->level = level; - raw->option_name = option_name; + raw->optname = optname; - Result rc = serviceIpcDispatch(&g_bsdSrv); - int ret = -1; - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 ret; - u32 errno; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - g_Errno = resp->errno; - ret = resp->ret; - } - } - - if (R_FAILED(rc)) { - g_Errno = EPIPE; - } - - return ret; + return _bsdDispatchBasicCommand(&c, NULL); } -int bsdWrite(int sockfd, const void* buffer, size_t length) { +int bsdShutdown(int sockfd, int how) { IpcCommand c; ipcInitialize(&c); - ipcAddSendBuffer(&c, buffer, length, 0); - ipcAddSendStatic(&c, buffer, length, 0); struct { u64 magic; u64 cmd_id; - u32 sockfd; + int sockfd; + int how; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 22; + raw->sockfd = sockfd; + raw->how = how; + + return _bsdDispatchBasicCommand(&c, NULL); +} + +int bsdShutdownAllSockets(int how) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + int how; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 23; + raw->how = how; + + return _bsdDispatchBasicCommand(&c, NULL); +} + +ssize_t bsdWrite(int fd, const char *buf, size_t count) { + IpcCommand c; + ipcInitialize(&c); + ipcAddSendBuffer(&c, buf, count, 0); + ipcAddSendStatic(&c, buf, count, 0); + + struct { + u64 magic; + u64 cmd_id; + int fd; } *raw; raw = ipcPrepareHeader(&c, sizeof(*raw)); raw->magic = SFCI_MAGIC; raw->cmd_id = 24; - raw->sockfd = sockfd; + raw->fd = fd; - Result rc = serviceIpcDispatch(&g_bsdSrv); - int ret = -1; - - if (R_SUCCEEDED(rc)) { - IpcParsedCommand r; - ipcParse(&r); - - struct { - u64 magic; - u64 result; - u32 ret; - u32 errno; - } *resp = r.Raw; - - rc = resp->result; - - if (R_SUCCEEDED(rc)) { - g_Errno = resp->errno; - ret = resp->ret; - } - } - - if (R_FAILED(rc)) { - g_Errno = EPIPE; - } - - return ret; + return _bsdDispatchBasicCommand(&c, NULL); +} + +ssize_t bsdRead(int fd, void *buf, size_t count) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buf, count, 0); + ipcAddRecvStatic(&c, buf, count, 0); + + struct { + u64 magic; + u64 cmd_id; + int fd; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 25; + raw->fd = fd; + + return _bsdDispatchBasicCommand(&c, NULL); +} + +int bsdClose(int fd) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + int fd; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 26; + raw->fd = fd; + + return _bsdDispatchBasicCommand(&c, NULL); +} + +int bsdDuplicateSocket(int sockfd) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + int sockfd; + u64 reserved; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 27; + raw->sockfd = sockfd; + raw->reserved = 0; + + return _bsdDispatchBasicCommand(&c, NULL); }