diff --git a/libctru/include/3ds/services/soc.h b/libctru/include/3ds/services/soc.h index dfb39d6..26d68e8 100644 --- a/libctru/include/3ds/services/soc.h +++ b/libctru/include/3ds/services/soc.h @@ -6,6 +6,94 @@ */ #pragma once #include +#include + +/// The config level to be used with @ref SOCU_GetNetworkOpt +#define SOL_CONFIG 0xfffe + +/// Options to be used with @ref SOCU_GetNetworkOpt +typedef enum +{ + NETOPT_MAC_ADDRESS = 0x1004, ///< The mac address of the interface (u32 mac[6]) + NETOPT_ARP_TABLE = 0x3002, ///< The ARP table @see SOCU_ARPTableEntry + NETOPT_IP_INFO = 0x4003, ///< The cureent IP setup @see SOCU_IPInfo + NETOPT_IP_MTU = 0x4004, ///< The value of the IP MTU (u32) + NETOPT_ROUTING_TABLE = 0x4006, ///< The routing table @see SOCU_RoutingTableEntry + NETOPT_UDP_NUMBER = 0x8002, ///< The number of sockets in the UDP table (u32) + NETOPT_UDP_TABLE = 0x8003, ///< The table of opened UDP sockets @see SOCU_UDPTableEntry + NETOPT_TCP_NUMBER = 0x9002, ///< The number of sockets in the TCP table (u32) + NETOPT_TCP_TABLE = 0x9003, ///< The table of opened TCP sockets @see SOCU_TCPTableEntry + NETOPT_DNS_TABLE = 0xB003, ///< The table of the DNS servers @see SOCU_DNSTableEntry -- Returns a buffer of size 336 but only 2 entries are set ? +} NetworkOpt; + +/// One entry of the ARP table retrieved by using @ref SOCU_GetNetworkOpt and @ref NETOPT_ARP_TABLE +typedef struct +{ + u32 unk0; // often 2 ? state ? + struct in_addr ip; ///< The IPv4 address associated to the entry + u8 mac[6]; ///< The MAC address of associated to the entry + u8 padding[2]; +} SOCU_ARPTableEntry; + +/// Structure returned by @ref SOCU_GetNetworkOpt when using @ref NETOPT_IP_INFO +typedef struct +{ + struct in_addr ip; ///< Current IPv4 address + struct in_addr netmask; ///< Current network mask + struct in_addr broadcast; ///< Current network broadcast address +} SOCU_IPInfo; + +// Linux netstat flags +// NOTE : there are probably other flags supported, if you can forge ICMP requests please check for D and M flags + +/** The route uses a gateway */ +#define ROUTING_FLAG_G 0x01 + +/// One entry of the routing table retrieved by using @ref SOCU_GetNetworkOpt and @ref NETOPT_ROUTING_TABLE +typedef struct +{ + struct in_addr dest_ip; ///< Destination IP address of the route + struct in_addr netmask; ///< Mask used for this route + struct in_addr gateway; ///< Gateway address to reach the network + u32 flags; ///< Linux netstat flags @see ROUTING_FLAG_G + u64 time; ///< number of milliseconds since 1st Jan 1900 00:00. +} SOCU_RoutingTableEntry; + +/// One entry of the UDP sockets table retrieved by using @ref SOCU_GetNetworkOpt and @ref NETOPT_UDP_TABLE +typedef struct +{ + struct sockaddr_storage local; ///< Local address information + struct sockaddr_storage remote; ///< Remote address information +} SOCU_UDPTableEntry; + +///@name TCP states +///@{ +#define TCP_STATE_CLOSED 1 +#define TCP_STATE_LISTEN 2 +#define TCP_STATE_ESTABLISHED 5 +#define TCP_STATE_FINWAIT1 6 +#define TCP_STATE_FINWAIT2 7 +#define TCP_STATE_CLOSE_WAIT 8 +#define TCP_STATE_LAST_ACK 9 +#define TCP_STATE_TIME_WAIT 11 +///@} + +/// One entry of the TCP sockets table retrieved by using @ref SOCU_GetNetworkOpt and @ref NETOPT_TCP_TABLE +typedef struct +{ + u32 state; ///< @see TCP states defines + struct sockaddr_storage local; ///< Local address information + struct sockaddr_storage remote; ///< Remote address information +} SOCU_TCPTableEntry; + +/// One entry of the DNS servers table retrieved by using @ref SOCU_GetNetworkOpt and @ref NETOPT_DNS_TABLE +typedef struct +{ + u32 family; /// Family of the address of the DNS server + struct in_addr ip; /// IP of the DNS server + u8 padding[12]; // matches the length required for IPv6 addresses +} SOCU_DNSTableEntry; + /** * @brief Initializes the SOC service. @@ -35,6 +123,16 @@ int SOCU_ShutdownSockets(); int SOCU_CloseSockets(); +/** + * @brief Retrieves information from the network configuration. Similar to getsockopt(). + * @param level Only value allowed seems to be @ref SOL_CONFIG + * @param optname The option to be retrieved + * @param optval Will contain the output of the command + * @param optlen Size of the optval buffer, will be updated to hold the size of the output + * @return 0 if successful. -1 if failed, and errno will be set accordingly. Can also return a system error code. + */ +int SOCU_GetNetworkOpt(int level, NetworkOpt optname, void * optval, socklen_t * optlen); + /** * @brief Gets the system's IP address, netmask, and subnet broadcast * @return error diff --git a/libctru/source/services/soc/soc_getipinfo.c b/libctru/source/services/soc/soc_getipinfo.c index a52c701..84efe5f 100644 --- a/libctru/source/services/soc/soc_getipinfo.c +++ b/libctru/source/services/soc/soc_getipinfo.c @@ -1,54 +1,14 @@ #include "soc_common.h" #include <3ds/ipc.h> #include <3ds/result.h> - -typedef struct -{ - struct in_addr ip; - struct in_addr netmask; - struct in_addr broadcast; -} SOCU_IPInfo_t; +#include <3ds/services/soc.h> int SOCU_GetIPInfo(struct in_addr *ip, struct in_addr *netmask, struct in_addr *broadcast) { - int i, ret; - u32 *cmdbuf = getThreadCommandBuffer(); - u32 *staticbufs = getThreadStaticBuffers(); - u32 saved_threadstorage[2]; - SOCU_IPInfo_t info; - - cmdbuf[0] = IPC_MakeHeader(0x1A,3,0); //0x1A00C0 - cmdbuf[1] = 0xFFFE; - cmdbuf[2] = 0x4003; - cmdbuf[3] = sizeof(info); - - // Save the thread storage values - for(i = 0 ; i < 2 ; ++i) - saved_threadstorage[i] = staticbufs[i]; - - staticbufs[0] = IPC_Desc_StaticBuffer(sizeof(info), 0); - staticbufs[1] = (u32)&info; - - ret = svcSendSyncRequest(SOCU_handle); - - // Restore the thread storage values - for(i = 0 ; i < 2 ; ++i) - staticbufs[i] = saved_threadstorage[i]; - - if(R_FAILED(ret)) { - errno = SYNC_ERROR; - return ret; - } - - ret = cmdbuf[1]; - if(R_FAILED(ret)) { - errno = SYNC_ERROR; - return ret; - } - if(cmdbuf[2] != 0) - { - return cmdbuf[2]; - } + SOCU_IPInfo info; + socklen_t infolen = sizeof info; + int ret = SOCU_GetNetworkOpt(SOL_CONFIG,NETOPT_IP_INFO,&info,&infolen); + if(ret != 0) return ret; if(ip != NULL) *ip = info.ip; diff --git a/libctru/source/services/soc/soc_getnetworkopt.c b/libctru/source/services/soc/soc_getnetworkopt.c new file mode 100644 index 0000000..dc3f915 --- /dev/null +++ b/libctru/source/services/soc/soc_getnetworkopt.c @@ -0,0 +1,54 @@ +#include "soc_common.h" +#include <3ds/ipc.h> +#include <3ds/result.h> +#include <3ds/services/soc.h> + +int SOCU_GetNetworkOpt(int level, NetworkOpt optname, void * optval, socklen_t * optlen) +{ + int i, ret; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + u32 saved_threadstorage[2]; + + cmdbuf[0] = IPC_MakeHeader(0x1A,3,0); //0x1A00C0 + cmdbuf[1] = level; + cmdbuf[2] = optname; + cmdbuf[3] = *optlen; + + // Save the thread storage values + for(i = 0 ; i < 2 ; ++i) + saved_threadstorage[i] = staticbufs[i]; + + staticbufs[0] = IPC_Desc_StaticBuffer(*optlen, 0); + staticbufs[1] = (u32)optval; + + ret = svcSendSyncRequest(SOCU_handle); + + // Restore the thread storage values + for(i = 0 ; i < 2 ; ++i) + staticbufs[i] = saved_threadstorage[i]; + + if(R_FAILED(ret)) { + errno = SYNC_ERROR; + return ret; + } + + ret = (int)cmdbuf[1]; + if(R_FAILED(ret)) + { + errno = SYNC_ERROR; + return ret; + + } + + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + errno = -ret; + return -1; + } + + *optlen = cmdbuf[3]; + + return ret; +}