diff --git a/include/dolphin/ip.h b/include/dolphin/ip.h new file mode 100644 index 00000000..740f452b --- /dev/null +++ b/include/dolphin/ip.h @@ -0,0 +1,47 @@ +#ifndef __DOLPHIN_OS_IP_H__ +#define __DOLPHIN_OS_IP_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IPU32(ipBytes) (*(u32*)(ipBytes)) +#define IPEQ(ip0, ip1) (IPU32(ip0) == IPU32(ip1)) +#define IPNEQ(ip0, ip1) (IPU32(ip0) != IPU32(ip1)) + +#define IP_CLASSA(ip) (((ip)[0] & 0x80) == 0x00) /* 0 - 127 */ +#define IP_CLASSB(ip) (((ip)[0] & 0xC0) == 0x80) /* 128 - 191 */ +#define IP_CLASSC(ip) (((ip)[0] & 0xE0) == 0xC0) /* 192 - 223 */ +#define IP_CLASSD(ip) (((ip)[0] & 0xF0) == 0xE0) /* 224 - 239 | Multicasting */ +#define IP_CLASSE(ip) (((ip)[0] & 0xF8) == 0xF0) /* 240 - 255 | Experimental */ + +extern const u8 IPAddrAny[4]; + +char* IPAtoN(const char* dotted, u8* addr); +char* IPNtoA(const u8* addr); +BOOL IPRecoverGateway(const u8* dst); +BOOL IPAutoConfig(void); +s32 IPSetConfigError(IPInterface* interface, s32 err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IFFifo.h b/include/dolphin/ip/IFFifo.h new file mode 100644 index 00000000..d48dd894 --- /dev/null +++ b/include/dolphin/ip/IFFifo.h @@ -0,0 +1,39 @@ +#ifndef __DOLPHIN_OS_IP_IFFIFO_H__ +#define __DOLPHIN_OS_IP_IFFIFO_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct IFBlock { + // total size: 0x8 + u8* ptr; // offset 0x0, size 0x4 + s32 len; // offset 0x4, size 0x4 +} IFBlock; + +typedef struct IFFifo { + // total size: 0x10 + u8* buff; // offset 0x0, size 0x4 + s32 size; // offset 0x4, size 0x4 + u8* head; // offset 0x8, size 0x4 + s32 used; // offset 0xC, size 0x4 +} IFFifo; + +void IFFifoInit(IFFifo* fifo, void* buff, s32 size); +void * IFFifoAlloc(IFFifo* fifo, s32 len); +BOOL IFFifoFree(IFFifo* fifo, void* ptr, s32 len); +void IFDump(void* ptr, s32 len); + +u8* IFRingIn(u8* buf, s32 size, u8* head, s32 used, const u8* data, s32 len); +u8* IFRingOut(u8* buf, s32 size, u8* head, s32 used, u8* data, s32 len); +int IFRingGet(u8* buf, s32 size, u8* head, s32 used, IFVec* vec, s32 len); +u8* IFRingPut(u8* buf, s32 size, u8* head, s32 used, s32 len); +u8* IFRingInEx(u8* buf, s32 size, u8* head, s32 used, s32 offset, const u8* data, s32 * adv, IFBlock* blockTable, s32 maxblock); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IFQueue.h b/include/dolphin/ip/IFQueue.h new file mode 100644 index 00000000..c6eb5696 --- /dev/null +++ b/include/dolphin/ip/IFQueue.h @@ -0,0 +1,202 @@ +#ifndef __DOLPHIN_OS_IF_QUEUE_H__ +#define __DOLPHIN_OS_IF_QUEUE_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct IFQueue IFQueue; +typedef struct IFQueue IFLink; + +struct IFQueue { + // total size: 0x8 + IFQueue* next; // offset 0x0, size 0x4 + IFQueue* prev; // offset 0x4, size 0x4 +}; + +#define IFQueueInit(queue) ((queue)->next = (queue)->prev = 0) +#define IFIsEmptyQueue(queue) ((queue)->next == 0) + +#define IFQueueIterator(type, queue, iter, n) \ + for ((iter) = (type)((queue)->next), (n) = ((iter) == 0) ? 0 : (type)(iter)->link.next; \ + (iter) != 0; \ + (iter) = (n), (n) = ((iter) == 0) ? 0 : (type)(iter)->link.next) + +#define IFQueueReverseIterator(type, queue, iter, p) \ + for ((iter) = (type)((queue)->prev), (p) = ((iter) == 0) ? 0 : (type)(iter)->link.prev; \ + (iter) != 0; \ + (iter) = (p), (p) = ((iter) == 0) ? 0 : (type)(iter)->link.prev) + +#define IFQueueDequeueEntry(type, queue, entry) \ +do { \ + register IFQueue* ___next; \ + register IFQueue* ___prev; \ + \ + ___next = (entry)->link.next; \ + ___prev = (entry)->link.prev; \ + \ + if (___next == 0) { \ + (queue)->prev = ___prev; \ + } else { \ + ((type)___next)->link.prev = ___prev; \ + } \ + if (___prev == 0){ \ + (queue)->next = ___next; \ + } else { \ + ((type)___prev)->link.next = ___next; \ + } \ +} while (0) + +#define IFQueueDequeueHead(type, queue, entry) \ +do { \ + register IFQueue* ___next; \ + \ + (entry) = (type)(queue)->next; \ + ___next = ((type)(entry))->link.next; \ + \ + if (___next == 0) { \ + (queue)->prev = 0; \ + } else { \ + ((type)___next)->link.prev = 0; \ + } \ + (queue)->next = ___next; \ +} while (0) + +#define IFQueueDequeueTail(type, queue, entry) \ +do { \ + register IFQueue* ___prev; \ + \ + (entry) = (type)(queue)->prev; \ + ___prev = ((type)(entry))->link.prev; \ + \ + if (___prev == 0) { \ + (queue)->next = 0; \ + } else { \ + ((type)___prev)->link.next = 0; \ + } \ + (queue)->prev = ___prev; \ +} while (0) + +#define IFQueueEnqueueHead(type, queue, entry) \ +do { \ + register IFQueue* ___next; \ + \ + ___next = (queue)->next; \ + \ + if (___next == 0) { \ + (queue)->prev = (IFQueue*)(entry); \ + } else { \ + ((type)___next)->link.prev = (IFQueue*)(entry); \ + } \ + (entry)->link.next = ___next; \ + (entry)->link.prev = 0; \ + (queue)->next = (IFQueue*)(entry); \ +} while (0) + +#define IFQueueEnqueueTail(type, queue, entry) \ +do { \ + register IFQueue* ___prev; \ + \ + ___prev = (queue)->prev; \ + \ + if (___prev == 0) { \ + (queue)->next = (IFQueue*)(entry); \ + } else { \ + ((type)___prev)->link.next = (IFQueue*)(entry); \ + } \ + (entry)->link.prev = ___prev; \ + (entry)->link.next = 0; \ + (queue)->prev = (IFQueue*)(entry); \ +} while (0) + +/* Macros where you can set the link member name */ + +#define IFQueueDequeueEntryLINK(type, queue, link, entry) \ +do { \ + register IFQueue* ___next; \ + register IFQueue* ___prev; \ + \ + ___next = (entry)->link.next; \ + ___prev = (entry)->link.prev; \ + \ + if (___next == 0) { \ + (queue)->prev = ___prev; \ + } else { \ + ((type)___next)->link.prev = ___prev; \ + } \ + if (___prev == 0){ \ + (queue)->next = ___next; \ + } else { \ + ((type)___prev)->link.next = ___next; \ + } \ +} while (0) + +#define IFQueueDequeueHeadLINK(type, queue, link, entry) \ +do { \ + register IFQueue* ___next; \ + \ + (entry) = (type)(queue)->next; \ + ___next = ((type)(entry))->link.next; \ + \ + if (___next == 0) { \ + (queue)->prev = 0; \ + } else { \ + ((type)___next)->link.prev = 0; \ + } \ + (queue)->next = ___next; \ +} while (0) + +#define IFQueueDequeueTailLINK(type, queue, link, entry) \ +do { \ + register IFQueue* ___prev; \ + \ + (entry) = (type)(queue)->prev; \ + ___prev = ((type)(entry))->link.prev; \ + \ + if (___prev == 0) { \ + (queue)->next = 0; \ + } else { \ + ((type)___prev)->link.next = 0; \ + } \ + (queue)->prev = ___prev; \ +} while (0) + +#define IFQueueEnqueueHeadLINK(type, queue, link, entry) \ +do { \ + register IFQueue* ___next; \ + \ + ___next = (queue)->next; \ + \ + if (___next == 0) { \ + (queue)->prev = (IFQueue*)(entry); \ + } else { \ + ((type)___next)->link.prev = (IFQueue*)(entry); \ + } \ + (entry)->link.next = ___next; \ + (entry)->link.prev = 0; \ + (queue)->next = (IFQueue*)(entry); \ +} while (0) + +#define IFQueueEnqueueTailLINK(type, queue, link, entry) \ +do { \ + register IFQueue* ___prev; \ + \ + ___prev = (queue)->prev; \ + \ + if (___prev == 0) { \ + (queue)->next = (IFQueue*)(entry); \ + } else { \ + ((type)___prev)->link.next = (IFQueue*)(entry); \ + } \ + (entry)->link.prev = ___prev; \ + (entry)->link.next = 0; \ + (queue)->prev = (IFQueue*)(entry); \ +} while (0) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IPArp.h b/include/dolphin/ip/IPArp.h new file mode 100644 index 00000000..98261964 --- /dev/null +++ b/include/dolphin/ip/IPArp.h @@ -0,0 +1,67 @@ +#ifndef __DOLPHIN_OS_IP_ARP_H__ +#define __DOLPHIN_OS_IP_ARP_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define ARP_FOUND 0 +#define ARP_LOOPBACK 1 +#define ARP_BROADCAST 2 +#define ARP_MULTICAST 3 +#define ARP_NOTFOUND -1 + +#define ARP_CACHE_RESOVLED 2 +#define ARP_CACHE_POLLING 3 + +typedef struct ARPCache { + // total size: 0xA8 + IFQueue link; // offset 0x0, size 0x8 + OSAlarm alarm; // offset 0x8, size 0x28 + int rxmit; // offset 0x30, size 0x4 + int state; // offset 0x34, size 0x4 + u8 hwAddr[6]; // offset 0x38, size 0x6 + u8 prAddr[4]; // offset 0x3E, size 0x4 + IPInterface* interface; // offset 0x44, size 0x4 + IFDatagram datagram; // offset 0x48, size 0x3C + u8 arp[28]; // offset 0x84, size 0x1C + IFQueue queue; // offset 0xA0, size 0x8 +} ARPCache; + +typedef struct ARPHeader { + // total size: 0x8 + u16 hwType; // offset 0x0, size 0x2 + u16 prType; // offset 0x2, size 0x2 + u8 hwAddrLen; // offset 0x4, size 0x1 + u8 prAddrLen; // offset 0x5, size 0x1 + u16 opCode; // offset 0x6, size 0x2 +} ARPHeader; + +#define ARPHeader2MACAddr(header) ((u8*)(header) + sizeof(ARPHeader)) +#define ARPHeader2PrAddr(header) ((u8*)(header) + sizeof(ARPHeader) + (header)->hwAddrLen) +#define ArpHeader2HwAddr(header) ((u8*)(header) + sizeof(ARPHeader) + header->hwAddrLen + header->prAddrLen) +#define ARPHeader2Addr(header) ((u8*)(header) + sizeof(ARPHeader) + 2 * (header)->hwAddrLen + (header)->prAddrLen) + +void ARPDumpPacket(const ETHHeader* eh, s32 len); +void ARPDump(void); +void ARPInit(void); +s32 ARPLookup(IPInterface* interface, u8* prAddr, u8* hwAddr); +void ARPRevalidate(u8* prAddr); +void ARPAdd(IPInterface* interface, u8* prAddr, u8* hwAddr); +void ARPHold(IPInterface* interface, struct IFDatagram * datagram); +void ARPOut(IPInterface* interface, u16 opCode, const u8* dstPrAddr, const u8* dstHwAddr, const u8* srcPrAddr, ARPCache* cache); +void ARPGratuitous(IPInterface* interface); +void ARPProbe(IPInterface* interface, u8* prAddr); +void ARPClaim(IPInterface* interface, IPInterfaceConf* conf); +void ARPIn(IPInterface* interface, ETHHeader* eh, s32 len); +void ARPRefresh(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/dolphin/ip/IPDhcp.h b/include/dolphin/ip/IPDhcp.h new file mode 100644 index 00000000..dfe65bef --- /dev/null +++ b/include/dolphin/ip/IPDhcp.h @@ -0,0 +1,35 @@ +#ifndef __DOLPHIN_OS_IP_DHCP_H__ +#define __DOLPHIN_OS_IP_DHCP_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DHCP_OPT_DNS 6 + +typedef struct DHCPInfo { + // total size: 0x12C + u8 ipaddr[4]; // offset 0x0, size 0x4 + u8 netmask[4]; // offset 0x4, size 0x4 + u8 router[4]; // offset 0x8, size 0x4 + u8 dns1[4]; // offset 0xC, size 0x4 + u8 dns2[4]; // offset 0x10, size 0x4 + char domain[256]; // offset 0x114, size 0x100 + u16 mtu; // offset 0x114, size 0x2 + u8 broadcast[4]; // offset 0x116, size 0x4 + u8 lease; // offset 0x11C, size 0x4 + u8 server[4]; // offset 0x120, size 0x4 + u8 renewal; // offset 0x124, size 0x4 + u8 rebinding; // offset 0x128, size 0x4 +} DHCPInfo; + +int DHCPGetOpt(int opt, void* buf, int len); +BOOL DHCPGetStatus(DHCPInfo * info /* r28 */); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IPDns.h b/include/dolphin/ip/IPDns.h new file mode 100644 index 00000000..d09c928f --- /dev/null +++ b/include/dolphin/ip/IPDns.h @@ -0,0 +1,97 @@ +#ifndef __DOLPHIN_OS_IP_DNS_H__ +#define __DOLPHIN_OS_IP_DNS_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct DNSCommand DNSCommand; +typedef struct DNSInfo DNSInfo; + +typedef s32 (*DNSPreCallback)(DNSInfo*, DNSCommand*); +typedef void (*DNSPostCallback)(DNSCommand*, s32); +typedef void (*DNSCallback)(DNSInfo*, s32); + +struct DNSCommand { + // total size: 0x3C + DNSInfo* info; // offset 0x0, size 0x4 + IFLink link; // offset 0x4, size 0x8 + int func; // offset 0xC, size 0x4 + DNSPreCallback precallback; // offset 0x10, size 0x4 + DNSPostCallback callback; // offset 0x14, size 0x4 + s32* result; // offset 0x18, size 0x4 + union { + struct { + // total size: 0x10 + const char* name; // offset 0x0, size 0x4 + u8* addr; // offset 0x4, size 0x4 + s32 addrLen; // offset 0x8, size 0x4 + DNSCallback callback; // offset 0xC, size 0x4 + } ga; // offset 0x0, size 0x10 + struct { + // total size: 0xC + const u8* addr; // offset 0x0, size 0x4 + char* name; // offset 0x4, size 0x4 + DNSCallback callback; // offset 0x8, size 0x4 + } gn; // offset 0x0, size 0xC + struct { + // total size: 0x14 + const u8* query; // offset 0x0, size 0x4 + s32 queryLen; // offset 0x4, size 0x4 + u8* response; // offset 0x8, size 0x4 + s32 responseLen; // offset 0xC, size 0x4 + DNSCallback callback; // offset 0x10, size 0x4 + } lu; // offset 0x0, size 0x14 + struct { + // total size: 0x20 + const char* nodeName; // offset 0x0, size 0x4 + const char* servName; // offset 0x4, size 0x4 + u16 type; // offset 0x8, size 0x2 + int sockType; // offset 0xC, size 0x4 + u16 port; // offset 0x10, size 0x2 + u8* addrList; // offset 0x14, size 0x4 + char* cname; // offset 0x18, size 0x4 + DNSCallback callback; // offset 0x1C, size 0x4 + } ai; // offset 0x0, size 0x20 + struct { + // total size: 0xC + void* sa; // offset 0x0, size 0x4 + char* node; // offset 0x4, size 0x4 + unsigned int nodeLen; // offset 0x8, size 0x4 + } ni; // offset 0x0, size 0xC + } data; // offset 0x1C, size 0x20 +}; + +struct DNSInfo { + // total size: 0x560 + UDPInfo udp; // offset 0x0, size 0xF0 + IPSocket socket; // offset 0xF0, size 0x8 + DNSCallback callback; // offset 0xF8, size 0x4 + OSTime rxmit; // offset 0x100, size 0x8 + OSAlarm alarm; // offset 0x108, size 0x28 + u32 flag; // offset 0x130, size 0x4 + u8 query[512]; // offset 0x134, size 0x200 + s32 queryLen; // offset 0x334, size 0x4 + u8 response[512]; // offset 0x338, size 0x200 + s32 responseLen; // offset 0x538, size 0x4 + volatile s32 * result; // offset 0x53C, size 0x4 + u16 id; // offset 0x540, size 0x2 + int func; // offset 0x544, size 0x4 + u8* data; // offset 0x548, size 0x4 + s32 datalen; // offset 0x54C, size 0x4 + int ref; // offset 0x550, size 0x4 + OSThreadQueue queueThread; // offset 0x54C, size 0x8 +}; + +s32 DNSClose(DNSInfo * info /* r31 */); +s32 DNSOpen(DNSInfo * info /* r1+0x8 */, const unsigned char * addr /* r1+0xC */); +s32 DNSOpen2(DNSInfo * info /* r31 */, const unsigned char * dns1 /* r27 */, const unsigned char * dns2 /* r28 */); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IPEther.h b/include/dolphin/ip/IPEther.h new file mode 100644 index 00000000..1251fed0 --- /dev/null +++ b/include/dolphin/ip/IPEther.h @@ -0,0 +1,26 @@ +#ifndef __DOLPHIN_OS_IP_ETHER_H__ +#define __DOLPHIN_OS_IP_ETHER_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ETHHeader { + // total size: 0xE + u8 dst[6]; // offset 0x0, size 0x6 + u8 src[6]; // offset 0x6, size 0x6 + u16 type; // offset 0xC, size 0x2 +} ETHHeader; + +BOOL IFMute(BOOL mute); +BOOL IFInit(s32 type /* r30 */); +void ETHOut(IPInterface* interface, IFDatagram* datagram); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/dolphin/ip/IPFrag.h b/include/dolphin/ip/IPFrag.h new file mode 100644 index 00000000..432291e5 --- /dev/null +++ b/include/dolphin/ip/IPFrag.h @@ -0,0 +1,22 @@ +#ifndef __DOLPHIN_OS_IP_FRAG_H__ +#define __DOLPHIN_OS_IP_FRAG_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IP_FRAG_BITS 0x1FFF +#define IP_HAS_FRAG 0x2000 +#define IP_DONT_FRAG 0x4000 + +#define IP_FRAG(ip) (((ip)->frag & IP_FRAG_BITS) << 3) + +IPHeader* IPReassemble(IPInterface* interface, IPHeader* frag, u32 flag); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IPIcmp.h b/include/dolphin/ip/IPIcmp.h new file mode 100644 index 00000000..e11b653c --- /dev/null +++ b/include/dolphin/ip/IPIcmp.h @@ -0,0 +1,17 @@ +#ifndef __DOLPHIN_OS_IP_ICMP_H__ +#define __DOLPHIN_OS_IP_ICMP_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +void ICMPIn(IPInterface * interface /* r27 */, IPHeader * ip /* r31 */, u32 flag /* r26 */); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IPIgmp.h b/include/dolphin/ip/IPIgmp.h new file mode 100644 index 00000000..079094e5 --- /dev/null +++ b/include/dolphin/ip/IPIgmp.h @@ -0,0 +1,29 @@ +#ifndef __DOLPHIN_OS_IP_IGMP_H__ +#define __DOLPHIN_OS_IP_IGMP_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct IGMP { + // total size: 0x8 + u8 vertype; // offset 0x0, size 0x1 + u8 unused; // offset 0x1, size 0x1 + u16 sum; // offset 0x2, size 0x2 + u8 addr[4]; // offset 0x4, size 0x4 +} IGMP; + +s32 IPMulticastLookup(const u8* groupAddr, const u8* interface); +s32 IPMulticastJoin(const u8* groupAddr, const u8* interface); +s32 IPMulticastLeave(const u8* groupAddr, const u8* interface); + +u16 IGMPCheckSum(IGMP* igmp); +void IGMPIn(IPInterface * interface /* r28 */, IPHeader * ip /* r30 */, u32 flag); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IPOpt.h b/include/dolphin/ip/IPOpt.h new file mode 100644 index 00000000..88f10ab0 --- /dev/null +++ b/include/dolphin/ip/IPOpt.h @@ -0,0 +1,23 @@ +#ifndef __DOLPHIN_OS_IP_OPT_H__ +#define __DOLPHIN_OS_IP_OPT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IP_OPT_TOS 7 +#define IP_OPT_TTL 8 +#define IP_OPT_9 9 +#define IP_OPT_MTTL 10 +#define IP_OPT_JOIN_MCAST 11 +#define IP_OPT_LEAVE_MCAST 12 + +s32 IPProcessSourceRoute(IPHeader* ip); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IPPpp.h b/include/dolphin/ip/IPPpp.h new file mode 100644 index 00000000..daae7230 --- /dev/null +++ b/include/dolphin/ip/IPPpp.h @@ -0,0 +1,58 @@ +#ifndef __DOLPHIN_OS_IP_PPP_H__ +#define __DOLPHIN_OS_IP_PPP_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct LCPHeader { + // total size: 0x4 + u8 code; // offset 0x0, size 0x1 + u8 id; // offset 0x1, size 0x1 + u16 len; // offset 0x2, size 0x2 +} LCPHeader; + +typedef struct PPPConf PPPConf; +typedef void (*PPPConfCallback)(PPPConf*); +typedef int (*PPPConfRecvCallback)(PPPConf*, LCPHeader*); +typedef int (*PPPConfTransCallback)(PPPConf*); + +struct PPPConf { + // total size: 0xA0 + u16 protocol; // offset 0x0, size 0x2 + int state; // offset 0x4, size 0x4 + u8 id; // offset 0x8, size 0x1 + u8 idTerminate; // offset 0x9, size 0x1 + u8 idReject; // offset 0xA, size 0x1 + u8 idEcho; // offset 0xB, size 0x1 + int rxmit; // offset 0xC, size 0x4 + int configure; // offset 0x10, size 0x4 + int terminate; // offset 0x14, size 0x4 + int failure; // offset 0x18, size 0x4 + u8 data[20]; // offset 0x1C, size 0x14 + u16 len; // offset 0x30, size 0x2 + OSAlarm alarm; // offset 0x38, size 0x28 + IPInterface* interface; // offset 0x60, size 0x4 + PPPConfRecvCallback receiveConfigureRequest; // offset 0x64, size 0x4 + PPPConfRecvCallback receiveConfigureAck; // offset 0x68, size 0x4 + PPPConfRecvCallback receiveConfigureNak; // offset 0x6C, size 0x4 + PPPConfRecvCallback receiveConfigureReject; // offset 0x70, size 0x4 + PPPConfTransCallback up; // offset 0x74, size 0x4 + PPPConfTransCallback down; // offset 0x78, size 0x4 + PPPConfTransCallback started; // offset 0x7C, size 0x4 + PPPConfTransCallback finished; // offset 0x80, size 0x4 + PPPConfCallback callback; // offset 0x84, size 0x4 + IFLink link; // offset 0x88, size 0x8 + u16 mru; // offset 0x90, size 0x2 + u16 auth; // offset 0x92, size 0x2 + u32 magic; // offset 0x94, size 0x4 + u32 remote; // offset 0x98, size 0x4 +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IPRoute.h b/include/dolphin/ip/IPRoute.h new file mode 100644 index 00000000..4d09f311 --- /dev/null +++ b/include/dolphin/ip/IPRoute.h @@ -0,0 +1,19 @@ +#ifndef __DOLPHIN_OS_IP_ROUTE_H__ +#define __DOLPHIN_OS_IP_ROUTE_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +IPInterface* IPGetRoute(const u8* addr, u8* dst); +BOOL IPIsBroadcastAddr(IPInterface* interface, const u8* addr); +BOOL IPIsLoopbackAddr(IPInterface* interface, const u8* addr); +void IPSetMtu(IPInterface * interface /* r31 */, s32 mtu /* r30 */); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IPSocket.h b/include/dolphin/ip/IPSocket.h new file mode 100644 index 00000000..1231d208 --- /dev/null +++ b/include/dolphin/ip/IPSocket.h @@ -0,0 +1,117 @@ +#ifndef __DOLPHIN_OS_IP_SOCKET_H__ +#define __DOLPHIN_OS_IP_SOCKET_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SO_MTU_MAX 1500 + +#define SO_GET_CONFIG_MTU(config) ((config)->mtu >= SO_MTU_MAX ? SO_MTU_MAX : (config)->mtu) + +typedef struct SOInAddr { + // total size: 0x4 + u32 addr; // offset 0x0, size 0x4 +} SOInAddr; + +typedef struct SOSockAddrIn { + u8 len; + u8 family; + u16 port; + SOInAddr addr; +} SOSockAddrIn; + +typedef struct SOIpMreq { + // total size: 0x8 + SOInAddr multiaddr; // offset 0x0, size 0x4 + SOInAddr interface; // offset 0x4, size 0x4 +} SOIpMreq; + +typedef struct SONode { + // total size: 0x38 + u8 proto; // offset 0x0, size 0x1 + u8 flag; // offset 0x1, size 0x1 + s16 ref; // offset 0x2, size 0x2 + IPInfo* info; // offset 0x4, size 0x4 + OSMutex mutexRead; // offset 0x8, size 0x18 + OSMutex mutexWrite; // offset 0x20, size 0x18 +} SONode; + +typedef struct SOSockAddr { + // total size: 0x8 + u8 len; // offset 0x0, size 0x1 + u8 family; // offset 0x1, size 0x1 + u8 data[6]; // offset 0x2, size 0x6 +} SOSockAddr; + +typedef struct SOHostEnt { + // total size: 0x10 + char* name; // offset 0x0, size 0x4 + char** aliases; // offset 0x4, size 0x4 + s16 addrType; // offset 0x8, size 0x2 + s16 length; // offset 0xA, size 0x2 + u8** addrList; // offset 0xC, size 0x4 +} SOHostEnt; + +typedef struct SOResolver { + // total size: 0x790 + DNSInfo info; // offset 0x0, size 0x560 + SOHostEnt ent; // offset 0x560, size 0x10 + char name[255]; // offset 0x570, size 0xFF + char* zero; // offset 0x670, size 0x4 + u8 addrList[140]; // offset 0x674, size 0x8C + u8* ptrList[36]; // offset 0x700, size 0x90 + u8 dns1[4]; // offset 0x790, size 0x4 + u8 dns2[4]; // offset 0x794, size 0x4 +} SOResolver; + +typedef void* (*SOAllocFunc)(u32, s32); +typedef void (*SOFreeFunc)(u32, void*, s32); + +typedef struct SOConfig { + // total size: 0x60 + u16 vendor; // offset 0x0, size 0x2 + u16 version; // offset 0x2, size 0x2 + SOAllocFunc alloc; // offset 0x4, size 0x4 + SOFreeFunc free; // offset 0x8, size 0x4 + u32 flag; // offset 0xC, size 0x4 + SOInAddr addr; // offset 0x10, size 0x4 + SOInAddr netmask; // offset 0x14, size 0x4 + SOInAddr router; // offset 0x18, size 0x4 + SOInAddr dns1; // offset 0x1C, size 0x4 + SOInAddr dns2; // offset 0x20, size 0x4 + s32 timeWaitBuffer; // offset 0x24, size 0x4 + s32 reassemblyBuffer; // offset 0x28, size 0x4 + s32 mtu; // offset 0x2C, size 0x4 + s32 rwin; // offset 0x30, size 0x4 + OSTime r2; // offset 0x38, size 0x8 + const char* peerid; // offset 0x40, size 0x4 + const char* passwd; // offset 0x44, size 0x4 + const char* serviceName; // offset 0x48, size 0x4 + const char* acName; // offset 0x4C, size 0x4 + s32 rdhcp; // offset 0x50, size 0x4 +} SOConfig; + +typedef struct SOLinger { + // total size: 0x8 + int onoff; // offset 0x0, size 0x4 + int linger; // offset 0x4, size 0x4 +} SOLinger; + +typedef struct SOPollFD { + // total size: 0x8 + int fd; // offset 0x0, size 0x4 + s16 events; // offset 0x4, size 0x2 + s16 revents; // offset 0x6, size 0x2 +} SOPollFD; + +s32 SOGetHostID(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IPTcp.h b/include/dolphin/ip/IPTcp.h new file mode 100644 index 00000000..ae4053a3 --- /dev/null +++ b/include/dolphin/ip/IPTcp.h @@ -0,0 +1,145 @@ +#ifndef __DOLPHIN_OS_IP_TCP_H__ +#define __DOLPHIN_OS_IP_TCP_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define TCP_STATE_LISTEN 1 + +#define TCP_FLAG_FIN (1 << 0) +#define TCP_FLAG_SYN (1 << 1) +#define TCP_FLAG_RST (1 << 2) +#define TCP_FLAG_PSH (1 << 3) +#define TCP_FLAG_ACK (1 << 4) +#define TCP_FLAG_URG (1 << 5) + +typedef struct TCPHeader { + // total size: 0x14 + u16 src; // offset 0x0, size 0x2 + u16 dst; // offset 0x2, size 0x2 + s32 seq; // offset 0x4, size 0x4 + s32 ack; // offset 0x8, size 0x4 + u16 flag; // offset 0xC, size 0x2 + u16 win; // offset 0xE, size 0x2 + u16 sum; // offset 0x10, size 0x2 + u16 urg; // offset 0x12, size 0x2 +} TCPHeader; + +typedef struct TCPSackHole { + // total size: 0x10 + s32 start; // offset 0x0, size 0x4 + s32 end; // offset 0x4, size 0x4 + int dupAcks; // offset 0x8, size 0x4 + s32 rxmit; // offset 0xC, size 0x4 +} TCPSackHole; + +typedef struct TCPInfo TCPInfo; +typedef void (*TCPCallback)(TCPInfo*, s32); + +struct TCPInfo { + // total size: 0x330 + IPInfo pair; // offset 0x0, size 0x20 + OSThreadQueue queueThread; // offset 0x20, size 0x8 + IPInterface* interface; // offset 0x28, size 0x4 + s32 err; // offset 0x2C, size 0x4 + s32 sendUna; // offset 0x30, size 0x4 + s32 sendNext; // offset 0x34, size 0x4 + s32 sendWin; // offset 0x38, size 0x4 + s32 sendUp; // offset 0x3C, size 0x4 + s32 sendWL1; // offset 0x40, size 0x4 + s32 sendWL2; // offset 0x44, size 0x4 + s32 iss; // offset 0x48, size 0x4 + s32 sendMaxWin; // offset 0x4C, size 0x4 + s32 sendMax; // offset 0x50, size 0x4 + s32 recvNext; // offset 0x54, size 0x4 + s32 recvWin; // offset 0x58, size 0x4 + s32 recvUp; // offset 0x5C, size 0x4 + s32 irs; // offset 0x60, size 0x4 + s32 segLen; // offset 0x64, size 0x4 + u8* segBegin; // offset 0x68, size 0x4 + IFBlock asb[4]; // offset 0x6C, size 0x20 + TCPSackHole scoreboard[4]; // offset 0x8C, size 0x40 + int sendHoles; // offset 0xCC, size 0x4 + s32 sendFack; // offset 0xD0, size 0x4 + s32 sendAwin; // offset 0xD4, size 0x4 + s32 rxmitData; // offset 0xD8, size 0x4 + s32 sendRecover; // offset 0xDC, size 0x4 + s32 lastSack; // offset 0xE0, size 0x4 + s32 state; // offset 0xE4, size 0x4 + u32 flag; // offset 0xE8, size 0x4 + TCPCallback closeCallback; // offset 0xEC, size 0x4 + s32* closeResult; // offset 0xF0, size 0x4 + s32 mss; // offset 0xF4, size 0x4 + volatile s32 sendBusy; // offset 0xF8, size 0x4 + u8 header[120]; // offset 0xFC, size 0x78 + u8* sendData; // offset 0x174, size 0x4 + s32 sendBuff; // offset 0x178, size 0x4 + u8* sendPtr; // offset 0x17C, size 0x4 + s32 sendLen; // offset 0x180, size 0x4 + IFDatagram datagram; // offset 0x184, size 0x3C + IFVec vec[3]; // offset 0x1C0, size 0x18 + TCPCallback sendCallback; // offset 0x1D8, size 0x4 + s32* sendResult; // offset 0x1DC, size 0x4 + s32 userAcked; // offset 0x1E0, size 0x4 + u8* userSendData; // offset 0x1E4, size 0x4 + s32 userSendLen; // offset 0x1E8, size 0x4 + OSTime lastSend; // offset 0x1F0, size 0x8 + u8* recvData; // offset 0x1F8, size 0x4 + s32 recvBuff; // offset 0x1FC, size 0x4 + s32 recvUser; // offset 0x200, size 0x4 + u8* recvPtr; // offset 0x204, size 0x4 + s32 recvAcked; // offset 0x208, size 0x4 + s32 dupAcks; // offset 0x20C, size 0x4 + TCPCallback recvCallback; // offset 0x210, size 0x4 + s32* recvResult; // offset 0x214, size 0x4 + u8* userData; // offset 0x218, size 0x4 + s32 userBuff; // offset 0x21C, size 0x4 + s32 userLen; // offset 0x220, size 0x4 + u8 oob; // offset 0x224, size 0x1 + s32 recvUrg; // offset 0x228, size 0x4 + TCPCallback urgCallback; // offset 0x22C, size 0x4 + s32* urgResult; // offset 0x230, size 0x4 + u8* urgData; // offset 0x234, size 0x4 + s32 rxmitCount; // offset 0x238, size 0x4 + OSTime rto; // offset 0x240, size 0x8 + OSTime r0; // offset 0x248, size 0x8 + OSTime r2; // offset 0x250, size 0x8 + OSAlarm rxmitAlarm; // offset 0x258, size 0x28 + s32 cWin; // offset 0x280, size 0x4 + s32 ssThresh; // offset 0x284, size 0x4 + BOOL rttTiming; // offset 0x288, size 0x4 + s32 rttSeq; // offset 0x28C, size 0x4 + OSTime rtt; // offset 0x290, size 0x8 + OSTime srtt; // offset 0x298, size 0x8 + OSTime rttDe; // offset 0x2A0, size 0x8 + OSTime rttMin; // offset 0x2A8, size 0x8 + OSTime rttMax; // offset 0x2B0, size 0x8 + TCPInfo* listening; // offset 0x2B8, size 0x4 + IPSocket* local; // offset 0x2BC, size 0x4 + IPSocket* remote; // offset 0x2C0, size 0x4 + IFQueue queueListen; // offset 0x2C4, size 0x8 + IFLink linkListen; // offset 0x2CC, size 0x8 + TCPCallback openCallback; // offset 0x2D4, size 0x4 + s32* openResult; // offset 0x2D8, size 0x4 + int linger; // offset 0x2DC, size 0x4 + OSAlarm lingerAlarm; // offset 0x2E0, size 0x28 + TCPInfo* logging; // offset 0x308, size 0x4 + IFQueue queueBacklog; // offset 0x30C, size 0x8 + IFQueue queueCompleted; // offset 0x314, size 0x8 + IFLink linkLog; // offset 0x31C, size 0x8 + s32 accepting; // offset 0x324, size 0x4 + void* node; // offset 0x328, size 0x4 +}; + +u16 TCPCheckSum(IFVec* vec, s32 nVec); +void TCPIn(IPInterface * interface /* r28 */, IPHeader * ip /* r29 */, u32 flag); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IPTcpTimeWait.h b/include/dolphin/ip/IPTcpTimeWait.h new file mode 100644 index 00000000..a3960deb --- /dev/null +++ b/include/dolphin/ip/IPTcpTimeWait.h @@ -0,0 +1,16 @@ +#ifndef __DOLPHIN_OS_IP_TCPTIMEWAIT_H__ +#define __DOLPHIN_OS_IP_TCPTIMEWAIT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +BOOL TCPLookupTimeWaitInfo(const u8* src, u16 srcPort, const u8* dst, u16 dstPort); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/IPUdp.h b/include/dolphin/ip/IPUdp.h new file mode 100644 index 00000000..bab13f50 --- /dev/null +++ b/include/dolphin/ip/IPUdp.h @@ -0,0 +1,53 @@ +#ifndef __DOLPHIN_OS_IP_UDP_H__ +#define __DOLPHIN_OS_IP_UDP_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct UDPHeader { + // total size: 0x8 + u16 src; // offset 0x0, size 0x2 + u16 dst; // offset 0x2, size 0x2 + u16 len; // offset 0x4, size 0x2 + u16 sum; // offset 0x6, size 0x2 +} UDPHeader; + +typedef struct UDPInfo UDPInfo; +typedef void (*UDPCallback)(UDPInfo*, s32); + +struct UDPInfo { + // total size: 0xF0 + IPInfo pair; // offset 0x0, size 0x20 + OSThreadQueue queueThread; // offset 0x20, size 0x8 + u32 flag; // offset 0x28, size 0x4 + UDPCallback sendCallback; // offset 0x2C, size 0x4 + s32* sendResult; // offset 0x30, size 0x4 + IFDatagram datagram; // offset 0x34, size 0x3C + IFVec vec[1]; // offset 0x70, size 0x8 + u8 header[68]; // offset 0x78, size 0x44 + UDPCallback recvCallback; // offset 0xBC, size 0x4 + s32* recvResult; // offset 0xC0, size 0x4 + void* data; // offset 0xC4, size 0x4 + s32 len; // offset 0xC8, size 0x4 + IPSocket* local; // offset 0xCC, size 0x4 + IPSocket* remote; // offset 0xD0, size 0x4 + u8* recvRing; // offset 0xD4, size 0x4 + s32 recvBuff; // offset 0xD8, size 0x4 + u8* recvPtr; // offset 0xDC, size 0x4 + s32 recvUsed; // offset 0xE0, size 0x4 + u8* sendData; // offset 0xE4, size 0x4 + s32 sendBuff; // offset 0xE8, size 0x4 + s32 sendUsed; // offset 0xEC, size 0x4 +}; + +u16 UDPCheckSum(IFVec* vec, s32 nVec); +void UDPIn(IPInterface * interface /* r25 */, struct IPHeader * ip /* r30 */, unsigned long flag /* r27 */); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/ip/ip.h b/include/dolphin/ip/ip.h index 6ffaa80b..436d8df0 100644 --- a/include/dolphin/ip/ip.h +++ b/include/dolphin/ip/ip.h @@ -1,26 +1,142 @@ -#ifndef _DOLPHIN_IP_H_ -#define _DOLPHIN_IP_H_ +#ifndef __DOLPHIN_OS_IP_IP_H__ +#define __DOLPHIN_OS_IP_IP_H__ #include +#include +#include -// Protocols -#define IP_PROTO_ICMP 1 -#define IP_PROTO_TCP 6 -#define IP_PROTO_UDP 17 +#ifdef __cplusplus +extern "C" { +#endif + +#define IP_SOCKLEN 8 +#define IF_MAX_VEC 4 + +#define IP_HLEN(ip) (((ip)->verlen & 0xF) << 2) + +#define IP_INET 2 + +// TODO: where does this go? IPEth? IPArp? +#define ETH_IP 0x0800 + +/* Supported IP protocols */ +#define IP_PROTO_ICMP 0x01 +#define IP_PROTO_IGMP 0x02 +#define IP_PROTO_TCP 0x06 +#define IP_PROTO_UDP 0x11 + +typedef struct IPSocket { + // total size: 0x8 + u8 len; // offset 0x0, size 0x1 + u8 family; // offset 0x1, size 0x1 + u16 port; // offset 0x2, size 0x2 + u8 addr[4]; // offset 0x4, size 0x4 +} IPSocket; + +typedef struct IPInfo { + // total size: 0x20 + u8 proto; // offset 0x0, size 0x1 + u8 ttl; // offset 0x1, size 0x1 + u8 tos; // offset 0x2, size 0x1 + u8 mttl; // offset 0x3, size 0x1 + s16 poll; // offset 0x4, size 0x2 + u16 flag; // offset 0x6, size 0x2 + IPSocket local; // offset 0x8, size 0x8 + IPSocket remote; // offset 0x10, size 0x8 + IFLink link; // offset 0x18, size 0x8 +} IPInfo; + +typedef struct IFVec { + // total size: 0x8 + void* data; // offset 0x0, size 0x4 + s32 len; // offset 0x4, size 0x4 +} IFVec; + +typedef struct IPInterface IPInterface; + +typedef struct IFDatagram { + // total size: 0x3C + IPInterface* interface; // offset 0x0, size 0x4 + IFQueue* queue; // offset 0x4, size 0x4 + IFLink link; // offset 0x8, size 0x8 + u16 type; // offset 0x10, size 0x2 + u8 hwAddr[6]; // offset 0x12, size 0x6 + u8 dst[4]; // offset 0x18, size 0x4 + u8 prefix[8]; // offset 0x1c, size 0x8 + u8 prefixLen; // offset 0x24, size 0x1 + u8 flag; // offset 0x25, size 0x1 + void (*callback)(void*, s32); // offset 0x28, size 0x4 + void* param; // offset 0x2C, size 0x4 + s32 nVec; // offset 0x30, size 0x4 + IFVec vec[1]; // offset 0x34, size 0x8 +} IFDatagram; + +typedef struct IPInterfaceConf { + // total size: 0x40 + IPInterface* interface; // offset 0x0, size 0x4 + IFQueue link; // offset 0x4, size 0x8 + u8 addr[4]; // offset 0xC, size 0x4 + OSAlarm alarm; // offset 0x10, size 0x28 + s32 count; // offset 0x38, size 0x4 + void (* callback)(void *, long); // offset 0x3C, size 0x4 +} IPInterfaceConf; + +typedef struct IPInterfaceStat { + // total size: 0x24 + u32 inUcastPackets; // offset 0x0, size 0x4 + u32 inNonUcastPackets; // offset 0x4, size 0x4 + u32 inDiscards; // offset 0x8, size 0x4 + u32 inErrors; // offset 0xC, size 0x4 + u32 outUcastPackets; // offset 0x10, size 0x4 + u32 outNonUcastPackets; // offset 0x14, size 0x4 + u32 outDiscards; // offset 0x18, size 0x4 + u32 outErrors; // offset 0x1C, size 0x4 + u32 outCollisions; // offset 0x20, size 0x4 +} IPInterfaceStat; + +struct IPInterface { + // total size: 0xA8 + s32 type; // offset 0x0, size 0x4 + BOOL up; // offset 0x4, size 0x4 + s32 err; // offset 0x8, size 0x4 + OSAlarm gratuitousAlarm; // offset 0x10, size 0x28 + u8 mac[6]; // offset 0x38, size 0x6 + s32 mtu; // offset 0x40, size 0x4 + u8 addr[4]; // offset 0x44, size 0x4 + u8 netmask[4]; // offset 0x48, size 0x4 + u8 broadcast[4]; // offset 0x4C, size 0x4 + u8 gateway[4]; // offset 0x50, size 0x4 + u8 alias[4]; // offset 0x54, size 0x4 + IFQueue ppp; // offset 0x58, size 0x8 + void (*out)(IPInterface*, IFDatagram*); // offset 0x60, size 0x4 + void (*cancel)(IPInterface*, IFDatagram*); // offset 0x48, size 0x4 + void* (*alloc)(IPInterface*, s32); // offset 0x68, size 0x4 + BOOL (*free)(IPInterface*, void*, s32); // offset 0x6c, size 0x4 + BOOL (*inFilter)(IPInterface*, void*, s32); // offset 0x70, size 0x4 + BOOL (*outFilter)(IPInterface*, void*, s32); // offset 0x74, size 0x4 + IFQueue queue; // offset 0x78, size 0x8 + IPInterfaceStat stat; // offset 0x80, size 0x24 +}; typedef struct IPHeader { - u8 verlen; - u8 tos; - u16 len; - u16 id; - u16 frag; - u8 ttl; - u8 proto; - u16 sum; - u8 src[4]; - u8 dst[4]; + // total size: 0x14 + u8 verlen; // offset 0x0, size 0x1 + u8 tos; // offset 0x1, size 0x1 + u16 len; // offset 0x2, size 0x2 + u16 id; // offset 0x4, size 0x2 + u16 frag; // offset 0x6, size 0x2 + u8 ttl; // offset 0x8, size 0x1 + u8 proto; // offset 0x9, size 0x1 + u16 sum; // offset 0xA, size 0x2 + u8 src[4]; // offset 0xC, size 0x4 + u8 dst[4]; // offset 0x10, size 0x4 } IPHeader; -BOOL IPIsLocalAddr(u32, const u8 *addr); +char* IPNtoA(const u8* addr); +void IFInitDatagram(IFDatagram* datagram, u16 type, int nVec); + +#ifdef __cplusplus +} +#endif #endif diff --git a/include/dolphin/os.h b/include/dolphin/os.h index b5952f99..55e3209d 100644 --- a/include/dolphin/os.h +++ b/include/dolphin/os.h @@ -136,7 +136,14 @@ BOOL OSRestoreInterrupts(BOOL level); #define OSSetVideoMode(on) OSSetEuRgb60Mode(on) #endif -#define OSHalt(msg) OSPanic(__FILE__, __LINE__, msg) +#define OSHalt(msg) OSPanic(__FILE__, __LINE__, msg) // TODO: get rid of #line usage + +// TODO: rename to OSHalt +#ifdef MATCHING +#define OSHaltLine(line, msg) OSPanic(__FILE__, line, msg) +#else +#define OSHaltLine(line, msg) OSPanic(__FILE__, __LINE__, msg) +#endif #ifdef _DEBUG diff --git a/include/dolphin/private/ip.h b/include/dolphin/private/ip.h new file mode 100644 index 00000000..313324cd --- /dev/null +++ b/include/dolphin/private/ip.h @@ -0,0 +1,21 @@ +#ifndef __IP_PRIVATE_H__ +#define __IP_PRIVATE_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern IPInterface __IFDefault; +extern SOResolver __SOResolver; +extern PPPConf PPPLcpConf; +extern PPPConf PPPIpcpConf; +extern const u8 IPLimited[4]; +extern IFQueue TCPInfoQueue; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/dolphin/tcp/tcp.h b/include/dolphin/tcp/tcp.h index 2de25604..fdfeca28 100644 --- a/include/dolphin/tcp/tcp.h +++ b/include/dolphin/tcp/tcp.h @@ -26,4 +26,6 @@ typedef struct TCPResetInfo { u16 id; } TCPResetInfo; + + #endif diff --git a/libs/PowerPC_EABI_Support/include/cstddef.h b/libs/PowerPC_EABI_Support/include/cstddef.h new file mode 100644 index 00000000..5051a861 --- /dev/null +++ b/libs/PowerPC_EABI_Support/include/cstddef.h @@ -0,0 +1,16 @@ +#ifndef _STDDEF_H_ +#define _STDDEF_H_ + +#define offsetof(type, member) ((size_t) &(((type *) 0)->member)) +#define membersize(type, member) (sizeof(((type*)0)->member)) + +#ifndef _SIZE_T_DEF +#define _SIZE_T_DEF +typedef unsigned long size_t; +#endif + +#ifndef NULL +#define NULL 0L +#endif + +#endif diff --git a/libs/dolphin/ip/IFFifo.c b/libs/dolphin/ip/IFFifo.c index e69de29b..3a9aca49 100644 --- a/libs/dolphin/ip/IFFifo.c +++ b/libs/dolphin/ip/IFFifo.c @@ -0,0 +1,211 @@ +#include "dolphin/os.h" +#include + +#ifdef DEBUG +#define IFFifoMemset(p, c, n) memset(p, c, n) +#else +#define IFFifoMemset(p, c, n) +#endif + +// Range: 0x0 -> 0x98 +void IFFifoInit(IFFifo* fifo /* r29 */, void* buff /* r30 */, s32 size /* r31 */) { + ASSERT(size == 0 || (buff && 0 < size)); + fifo->size = size; + fifo->buff = buff; + fifo->head = buff; + fifo->used = 0; + +#ifdef DEBUG + if (buff && size > 0) { + IFFifoMemset(buff, 0xFF, size); + } +#endif +} + +// Range: 0x98 -> 0x24C +static void* FifoAlloc(IFFifo* fifo /* r31 */, s32 len /* r28 */) { + // Local variables + s32 free; // r26 + u8* tail; // r29 + u8* end; // r27 + + end = fifo->buff + fifo->size; + ASSERT(0 < len); + ASSERT(0 <= fifo->used && fifo->used <= fifo->size); + ASSERT(fifo->buff <= fifo->head && fifo->head <= end); + + if (fifo->size - fifo->used < len) { + return NULL; + } + + tail = fifo->head + fifo->used; + if (end <= tail) { + tail -= fifo->size; + } + + if (fifo->head == tail) { + fifo->head = fifo->buff; + fifo->used = len; + return fifo->buff; + } else if (fifo->head < tail) { + free = (s32)(end - tail); + if (len <= free) { + fifo->used += len; + return tail; + } else if (len <= (s32)(fifo->head - fifo->buff)) { + fifo->used += free + len; + return fifo->buff; + } + } else { + ASSERT(fifo->head - tail == fifo->size - fifo->used); + fifo->used += len; + return tail; + } + + return NULL; +} + +// Range: 0x24C -> 0x2D0 +void * IFFifoAlloc(IFFifo* fifo /* r30 */, s32 len /* r29 */) { + // Local variables + void* ptr; // r31 + + ptr = FifoAlloc(fifo, len); + if (ptr) { + IFFifoMemset(ptr, 0xA3, len); + } + + ASSERT(fifo->used <= fifo->size); + return ptr; +} + +// Range: 0x2D0 -> 0x648 +BOOL IFFifoFree(IFFifo* fifo /* r31 */, void* ptr /* r1+0xC */, s32 len /* r26 */) { + // Local variables + u8* p; // r29 + u8* end; // r27 + u8* head; // r30 + u8* tail; // r28 + + p = (u8*)ptr; + end = fifo->buff + fifo->size; + ASSERT(0 <= fifo->used && fifo->used <= fifo->size); + ASSERT(fifo->buff <= fifo->head && fifo->head < end); + + if (len <= 0 || fifo->used < len || p == NULL || p < fifo->buff || end <= p) { + return FALSE; + } + + tail = fifo->head + fifo->used; + if (end <= tail) { + tail -= fifo->size; + } + + head = p + len; + if (end <= head) { + head -= fifo->size; + } + + if (head < fifo->buff || end <= head) { + return FALSE; + } + + if (fifo->head == tail) { + if (fifo->head < head) { + if (head <= p || p < fifo->head) { + return FALSE; + } + + IFFifoMemset(fifo->head, -0xA4, (size_t)(head - fifo->head)); + } else { + if (head <= p && p < fifo->head) { + return FALSE; + } + + if (head == tail) { + IFFifoMemset(p, -0xA4, len); + fifo->used -= len; + return TRUE; + } + + IFFifoMemset(fifo->head, -0xA4, (size_t)(end - fifo->head)); + IFFifoMemset(fifo->buff, -0xA4, (size_t)(head - fifo->buff)); + } + } else if (fifo->head < tail) { + if (head <= p || p < fifo->head || tail < head) { + return FALSE; + } + + if (head == tail) { + IFFifoMemset(p, -0xA4, len); + fifo->used -= len; + return TRUE; + } + + IFFifoMemset(fifo->head, -0xA4, (size_t)(head - fifo->head)); + } else if (fifo->head < head) { + if (head <= p || p < fifo->head) { + return FALSE; + } + + IFFifoMemset(fifo->head, -0xA4, (size_t)(head - fifo->head)); + } else { + if (tail < head) { + return FALSE; + } + + if (head <= p && p < fifo->head) { + return FALSE; + } + + if (head == tail) { + IFFifoMemset(p, -0xA4, len); + fifo->used -= len; + return TRUE; + } + + IFFifoMemset(fifo->head, -0xA4, (size_t)(end - fifo->head)); + IFFifoMemset(fifo->buff, -0xA4, (size_t)(head - fifo->buff)); + } + + if (head <= tail) { + fifo->used = (s32)tail - (s32)head; + } else { + fifo->used = ((s32)end - (s32)head) + ((s32)tail - (s32)fifo->buff); + } + + ASSERT(fifo->used < fifo->size); + fifo->head = head; + return TRUE; +} + +// Range: 0x648 -> 0x748 +void IFDump(void* ptr /* r28 */, s32 len /* r27 */) { + // Local variables + int j; // r30 + int i; // r31 + int n; // r29 + + for (j = 0; j < len; j += 16) { + n = len - j; + if (n > 16) { + n = 16; + } + + OSReport("%08x: ", j); + for (i = 0; i < n; i++) { + OSReport("%02x ", ((u8*)ptr)[j + i]); + } + + for (i; i < 16; i++) { + OSReport(" "); + } + + OSReport(" "); + for (i = 0; i < n; i++) { + OSReport("%c", isprint(((u8*)ptr)[j + i]) ? ((u8*)ptr)[j + i] : '.'); + } + + OSReport("\n"); + } +} diff --git a/libs/dolphin/ip/IFRing.c b/libs/dolphin/ip/IFRing.c index e69de29b..9eeb10df 100644 --- a/libs/dolphin/ip/IFRing.c +++ b/libs/dolphin/ip/IFRing.c @@ -0,0 +1,221 @@ +#include "dolphin/os.h" +#include + +// Range: 0x0 -> 0x10C +u8* IFRingIn(u8* buf /* r23 */, s32 size /* r24 */, u8* head /* r30 */, s32 used /* r22 */, const u8* data /* r26 */, s32 len /* r28 */) { + // Local variables + u8* end; // r25 + u8* tail; // r31 + s32 free; // r27 + + ASSERT(used + len <= size); + end = buf + size; + ASSERT(buf <= head && head < end); + tail = head + used; + if (end <= tail) { + tail -= size; + } + + if (head <= tail) { + free = (s32)end - (s32)tail; + if (len <= free) { + memmove(tail, data, len); + return head; + } else { + memmove(tail, data, free); + data += free; + len -= free; + memmove(buf, data, len); + return head; + } + } else { + memmove(tail, data, len); + return head; + } +} + +// Range: 0x10C -> 0x238 +u8* IFRingOut(u8* buf /* r25 */, s32 size /* r1+0xC */, u8* head /* r31 */, s32 used /* r1+0x14 */, u8* data /* r26 */, s32 len /* r29 */) { + // Local variables + u8* end; // r28 + s32 front; // r27 + + ASSERT(len <= used); + end = buf + size; + ASSERT(buf <= head && head < end); + + if (head + len < end) { + memmove(data, head, len); + head += len; + } else { + front = (s32)end - (s32)head; + ASSERT(front <= len); + memmove(data, head, front); + data += front; + len -= front; + head = buf; + memmove(data, head, len); + head += len; + } + + ASSERT(buf <= head && head < end); + return head; +} + +// Range: 0x238 -> 0x328 +int IFRingGet(u8* buf /* r25 */, s32 size /* r24 */, u8* head /* r31 */, s32 used /* r1+0x14 */, IFVec* vec /* r30 */, s32 len /* r27 */) { + // Local variables + u8* end; // r28 + s32 front; // r26 + + ASSERT(len <= used); + end = buf + size; + if (end <= head) { + head -= size; + } + ASSERT(buf <= head && head < end); + + if (head + len <= end) { + vec->data = head; + vec->len = len; + return 1; // one entry + } else { + front = (s32)end - (s32)head; + ASSERT(front < len); + vec->data = head; + vec->len = front; + vec++; + vec->data = buf; + vec->len = len - front; + return 2; // two entries + } +} + +// Range: 0x328 -> 0x3FC +u8* IFRingPut(u8* buf /* r27 */, s32 size /* r1+0xC */, u8* head /* r31 */, s32 used /* r1+0x14 */, s32 len /* r28 */) { + // Local variables + u8* end; // r29 + + ASSERT(len <= used); + end = buf + size; + ASSERT(buf <= head && head < end); + if (head + len < end) { + head += len; + } else { + head = (buf + len) - (end - head); + } + + ASSERT(buf <= head && head < end); + return head; +} + +// Range: 0x3FC -> 0x650 +static s32 MargeBlock(u8* ptr /* r23 */, s32 len /* r24 */, IFBlock* blockTable /* r25 */, s32 maxblock /* r20 */, s32 size /* r21 */, u8* tail /* r27 */) { + // Local variables + IFBlock* block; // r31 + IFBlock* end; // r28 + s32 pl; // r26 + s32 pr; // r30 + s32 pb; // r29 + + ASSERT(1 < maxblock && blockTable); + ASSERT(0 <= len); + + pl = tail <= ptr ? (s32)ptr - (s32)tail : (s32)ptr + size - (s32)tail; + pr = pl + len; + end = blockTable + maxblock; + if (tail == ptr) { + block = blockTable; + + while (block < end && block->ptr) { + pb = tail <= block->ptr ? (s32)block->ptr - (s32)tail : (s32)block->ptr + size - (s32)tail; + if (pb <= pr) { + pr = pb + block->len > pr ? pb + block->len : pr; + len = pr - pl; + memmove(block, block + 1, (s32)end - (s32)(block + 1)); + memset(end - 1, 0, sizeof(IFBlock)); + } else { + block++; + } + } + + return len; + } else { + block = blockTable; + while (block < end && block->ptr) { + pb = tail <= block->ptr ? (s32)block->ptr - (s32)tail : (s32)block->ptr + size - (s32)tail; + if (pl <= pb + block->len && pb <= pr) { + pr = pb + block->len > pr ? pb + block->len : pr; + + if (pb < pl) { + pl = pb; + ptr = block->ptr; + } + + len = pr - pl; + memmove(block, block + 1, (s32)end - (s32)(block + 1)); + memset(end - 1, 0, sizeof(IFBlock)); + } else { + block++; + } + } + + if (block < end) { + ASSERT(block->ptr == NULL); + block->ptr = ptr; + block->len = len; + } else { + memmove(blockTable, blockTable + 1, (s32)end - (s32)(blockTable + 1)); + block = end - 1; + block->ptr = ptr; + block->len = len; + } + + return 0; + } +} + +// Range: 0x650 -> 0x7D4 +u8* IFRingInEx(u8* buf /* r21 */, s32 size /* r27 */, u8* head /* r28 */, s32 used /* r19 */, s32 offset /* r22 */, const u8* data /* r23 */, s32 * adv /* r20 */, IFBlock* blockTable /* r1+0x24 */, s32 maxblock /* r1+0x68 */) { + // Local variables + u8* end; // r26 + u8* tail; // r25 + u8* ptr; // r31 + s32 len; // r29 + s32 free; // r24 + + len = *adv; + if (len == 0) { + return head; + } + + ASSERT(0 <= offset); + ASSERT(used + offset + len <= size); + end = buf + size; + ASSERT(buf <= head && head < end); + tail = head + used; + if (end <= tail) { + tail -= size; + } + + ASSERT(offset < size); + ptr = tail + offset; + if (end <= ptr) { + ptr -= size; + } + + if (head <= ptr) { + free = (s32)end - (s32)ptr; + if (len <= free) { + memmove(ptr, data, len); + } else { + memmove(ptr, data, free); + memmove(buf, data + free, len - free); + } + } else { + memmove(ptr, data, len); + } + + *adv = MargeBlock(ptr, len, blockTable, maxblock, size, tail); + return head; +} diff --git a/libs/dolphin/ip/IP.c b/libs/dolphin/ip/IP.c index e69de29b..5a12ff62 100644 --- a/libs/dolphin/ip/IP.c +++ b/libs/dolphin/ip/IP.c @@ -0,0 +1,645 @@ +#include +#include "types.h" +#include "stdio.h" + +static u16 Id = 1; +const u8 IPAddrAny[4] = { 0, 0, 0, 0 }; // 0.0.0.0 +const u8 IPLoopbackAddr[4] = { 127, 0, 0, 1 }; // 127.0.0.1 +const u8 IPLimited[4] = { 255, 255, 255, 255 }; // 255.255.255.255 + +void IPPrintAddr(u8* addr) { + OSReport("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); +} + +char* IPAtoN(const char* dotted, u8* addr) { + int c; + u32 part[4]; + int n; + u32 val; + int base; + + n = 0; + c = *dotted; + while (TRUE) { + if (isdigit(c) == FALSE) { + return NULL; + } + + base = 10; + if (c == '0') { + c = *(++dotted); + + if (c == 'x' || c == 'X') { + base = 16; + c = *(++dotted); + } else { + base = 8; + } + } + + val = 0; + while (TRUE) { + if (isdigit(c)) { + val *= base; + val = c + val; + val -= '0'; + } else { + if (base != 16 || isxdigit(c) == FALSE) { + break; + } + + val *= 16; + val += ((c + 10) - (islower(c) ? 'a' : 'A')); + } + + c = *(++dotted); + } + + part[n++] = val; + if (c == '.') { + if (n >= 4 || val > 255) { + return NULL; /* bad IP string */ + } + + c = *(++dotted); + } else if (c > '\x7F') { + return NULL; /* character out of standard ASCII range */ + } else { + switch (n) { + case 1: + addr[0] = (u8)(val >> 24); + addr[1] = (u8)(val >> 16); + addr[2] = (u8)(val >> 8); + addr[3] = (u8)(val >> 0); + break; + case 2: + if (0x00FFFFFF < val) { + return NULL; + } + + addr[0] = (u8)part[0]; + addr[1] = (u8)(val >> 16); + addr[2] = (u8)(val >> 8); + addr[3] = (u8)(val >> 0); + break; + case 3: + if (val > 0x0000FFFF) { + return NULL; + } + + addr[0] = (u8)part[0]; + addr[1] = (u8)part[1]; + addr[2] = (u8)(val >> 8); + addr[3] = (u8)(val >> 0); + break; + case 4: + addr[0] = (u8)part[0]; + addr[1] = (u8)part[1]; + addr[2] = (u8)part[2]; + addr[3] = (u8)val; + break; + default: + return NULL; + } + + return (char*)dotted; + } + } +} + +char* IPNtoA(const u8* addr) { + static char ascii[16]; + + sprintf(ascii, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); + return ascii; +} + +IPInfo* IPLookupInfo(IFQueue* queue, u8* srcAddr, u8* dstAddr, u16 src, u16 dst, u32 flag) { + IPInfo* info; + IPInfo* next; + int wildcard; + int minimum; + IPInfo* match; + s32 mcast; + + minimum = 3; + match = NULL; + + if (IP_CLASSD(dstAddr)) { + mcast = IPMulticastLookup(dstAddr, IPAddrAny); + + if (mcast < 0) { + return NULL; + } + } + + IFQueueIterator(IPInfo*, queue, info, next) { + if ( + (info->local.port != 0 && info->local.port == dst) && (!IP_CLASSD(dstAddr) || + ((info->flag & (1 << mcast)) != 0 && (((flag & 0x4) == 0) || ((info->flag & 0x8000) != 0)))) + ) { + wildcard = 0; + if (IPNEQ(dstAddr, IPAddrAny)) { + if (IPEQ(info->local.addr, IPAddrAny)) { + wildcard++; + } else if (IPNEQ(info->local.addr, dstAddr)) { + continue; + } + } else if (IPNEQ(info->local.addr, IPAddrAny)) { + wildcard++; + } + + if (IPNEQ(srcAddr, IPAddrAny)) { + if (IPEQ(info->remote.addr, IPAddrAny)) { + wildcard++; + } else if (info->remote.port != src || IPNEQ(info->remote.addr, srcAddr)) { + continue; + } + } else if (IPNEQ(info->remote.addr, IPAddrAny)) { + wildcard++; + } + + if (wildcard < minimum) { + match = info; + minimum = wildcard; + + if (minimum == 0) { + break; + } + } + } + } + + return match; +} + +BOOL __IPIsMember(IFQueue* queue, IPInfo* info) { + IPInfo* iter; + IPInfo* next; + + IFQueueIterator(IPInfo*, queue, iter, next) { + if (iter == info) { + return TRUE; + } + } + + return FALSE; +} + +BOOL IPBind(IFQueue* queue, IPInfo* info, const IPSocket* socket, BOOL reuse) { + IPInfo* iter; + IPInfo* next; + + if (socket->len != 8 || socket->family != 2 || socket->port == 0 || IP_CLASSE(socket->addr)) { + return -12; + } + + if (socket->port == 0 || (IPNEQ(socket->addr, IPAddrAny) && IPNEQ(socket->addr, IPLoopbackAddr) && + IPNEQ(socket->addr, __IFDefault.addr) && IPNEQ(socket->addr, __IFDefault.alias) && !IP_CLASSD(socket->addr))) { + return -13; + } + + IFQueueIterator(IPInfo*, queue, iter, next) { + if (iter != info && iter->local.port == socket->port && IPEQ(iter->local.addr, socket->addr) && + (reuse == FALSE || (iter->remote.port == info->remote.port && IPEQ(iter->remote.addr, info->remote.addr))) + ) { + return -5; + } + } + + memmove(&info->local, socket, sizeof(info->local)); + return 0; +} + +u16 IPGetAnonPort(IFQueue* queue, u16* last) { + u16 port; + IPInfo* info; + IPInfo* next; + int skip; + + skip = 0; + if (*last < 0x400 || *last > 0x1388) { + *last = 0x400; + } + +loop: + port = *last; + *last = port + 1; + if (*last > 0x1388) { + *last = 0x400; + } + + IFQueueIterator(IPInfo*, queue, info, next) { + if (info->local.port == port) { + if (++skip <= 0xf88) { + goto loop; + } + + return 0; + } + } + + return port; +} + +s32 IPConnect(IFQueue* queue, IPInfo* info, const IPSocket* socket, u16* last) { + IPInfo* iter; + IPInfo* next; + IPInterface* interface; + const u8* localAddr; + + if (socket == NULL || socket->len != 8 || socket->family != 2 || socket->port == 0 || IP_CLASSE(socket->addr)) { + return -12; + } + + if (IPEQ(socket->addr, IPAddrAny)) { + return -13; + } + + interface = IPGetRoute(socket->addr, NULL); + if (interface == NULL) { + return -2; + } + + if (info->proto == 6 && (IP_CLASSD(socket->addr) || IPIsBroadcastAddr(interface, socket->addr))) { + return -13; + } + + + if (IPEQ(info->local.addr, IPAddrAny)) { + if (socket->addr[0] == 127) { + localAddr = IPLoopbackAddr; + } else if (memcmp(socket->addr, interface->alias, 2) == 0 || IPEQ(interface->addr, IPAddrAny)) { + localAddr = interface->alias; + } else { + localAddr = interface->addr; + } + } else { + localAddr = info->local.addr; + } + + if (info->local.port == 0) { + do { + info->local.port = IPGetAnonPort(queue, last); + if (info->local.port == 0) { + return -7; + } + } while (info->proto == IP_PROTO_TCP && TCPLookupTimeWaitInfo(socket->addr, socket->port, localAddr, info->local.port)); + } else { + IFQueueIterator(IPInfo*, queue, iter, next) { + if (iter != info && iter->local.port == info->local.port && iter->remote.port == info->remote.port && + IPEQ(iter->local.addr, localAddr) && IPEQ(iter->remote.addr, info->remote.addr)) { + return -5; + } + } + + if (info->proto == IP_PROTO_TCP && TCPLookupTimeWaitInfo(socket->addr, socket->port, localAddr, info->local.port)) { + return -5; + } + } + + memmove(&info->remote, socket, sizeof(info->remote)); + if (IPEQ(info->local.addr, IPAddrAny)) { + memmove(info->local.addr, localAddr, sizeof(info->local.addr)); + } + + return 0; +} + +s32 IPGetRemoteSocket(IPInfo* info, IPSocket* socket) { + ASSERT(info->remote.len == IP_SOCKLEN); + ASSERT(info->remote.family == IP_INET); + memcpy(socket, &info->remote, sizeof(info->remote)); + return 0; +} + +s32 IPGetLocalSocket(IPInfo* info, IPSocket* socket) { + ASSERT(info->local.len == IP_SOCKLEN); + ASSERT(info->local.family == IP_INET); + memcpy(socket, &info->local, sizeof(info->local)); + return 0; +} + +s32 IPGetSockOpt(IPInfo* info, int level, int optname, void* optval, int* optlen) { + BOOL enabled; + s32 rc; + + rc = -14; + enabled = OSDisableInterrupts(); + if (level == 0) { + switch (optname) { + case IP_OPT_TOS: + if (*(u32*)optlen >= sizeof(u32)) { + *(u32*)optval = info->tos; + *optlen = sizeof(u32); + rc = 0; + } else { + rc = -12; + } + break; + case IP_OPT_TTL: + if (*(u32*)optlen >= sizeof(u32)) { + *(u32*)optval = info->ttl; + *optlen = sizeof(u32); + rc = 0; + } else { + rc = -12; + } + break; + case IP_OPT_9: + if (*(u32*)optlen >= sizeof(u8)) { + *(u8*)optval = (info->flag & 0x8000) ? TRUE : FALSE; + *optlen = sizeof(u8); + rc = 0; + } else { + rc = -12; + } + break; + case IP_OPT_MTTL: + if (*(u32*)optlen >= sizeof(info->mttl)) { + *(u8*)optval = info->mttl; + *optlen = sizeof(info->mttl); + rc = 0; + } else { + rc = -12; + } + break; + } + } + + OSRestoreInterrupts(enabled); + return rc; +} + +s32 IPSetSockOpt(IPInfo* info, int level, int optname, void* optval, int optlen) { + BOOL enabled; + s32 rc; + + rc = -14; + enabled = OSDisableInterrupts(); + + if (level == 0) { + switch (optname) { + case IP_OPT_TOS: + if (optlen >= sizeof(u32)) { + info->tos = *(s32*)optval < 255 ? *(u32*)optval : 255; + rc = 0; + } else { + rc = -12; + } + break; + case IP_OPT_TTL: + if (optlen >= sizeof(u32)) { + info->ttl = *(s32*)optval < 255 ? *(u32*)optval : 255; + rc = 0; + } else { + rc = -12; + } + break; + case IP_OPT_9: + if (optlen >= sizeof(u8)) { + if (*(u8*)optval) { + info->flag |= 0x8000; + } else { + info->flag &= ~0x8000; + } + + rc = 0; + } else { + rc = -12; + } + break; + case IP_OPT_MTTL: + if (optlen >= sizeof(info->mttl)) { + info->mttl = *(u8*)optval; + rc = 0; + } else { + rc = -12; + } + break; + case IP_OPT_JOIN_MCAST: + if (optlen >= sizeof(SOIpMreq)) { + const SOIpMreq* mreq = (const SOIpMreq*)optval; + + rc = IPMulticastLookup((u8*)&mreq->multiaddr.addr, (u8*)&mreq->interface.addr); + if (0 <= rc) { + if ((info->flag & (1 << rc)) == 0) { + rc = IPMulticastJoin((u8*)&mreq->multiaddr.addr, (u8*)&mreq->interface.addr); + ASSERT(0 <= rc); + info->flag |= 1 << rc; + } + + rc = 0; + } else { + rc = IPMulticastJoin((u8*)&mreq->multiaddr.addr,(u8*)&mreq->interface.addr); + if (0 <= rc) { + info->flag |= 1 << rc; + rc = 0; + } + } + } else { + rc = -12; + } + break; + case IP_OPT_LEAVE_MCAST: + if (optlen >= sizeof(SOIpMreq)) { + const SOIpMreq* mreq = (const SOIpMreq*)optval; + + rc = IPMulticastLookup((u8*)&mreq->multiaddr.addr, (u8*)&mreq->interface.addr); + if (0 <= rc) { + if ((info->flag & (1 << rc)) != 0) { + rc = IPMulticastLeave((u8*)&mreq->multiaddr.addr, (u8*)&mreq->interface.addr); + ASSERT(0 <= rc); + info->flag &= ~(1 << rc); + rc = 0; + } else { + rc = -4; + } + } + } else { + rc = -12; + } + break; + } + } + + OSRestoreInterrupts(enabled); + return rc; +} + +BOOL IPSetOption(IPInfo* info, u8 ttl, u8 tos) { + info->ttl = ttl; + info->tos = tos; + return TRUE; +} + +u16 IPCheckSum(IPHeader* ip) { + int len; + u32 sum; + u16* p; + + sum = 0; + len = IP_HLEN(ip); + p = (u16*)ip; + + for (; len > 0; len -= sizeof(u16)) { + sum += *p++; + } + + /* Add the 16-bit carry values twice and return the inverse */ + sum = (sum & 0xFFFF) + ((sum >> 16) & 0xFFFF); + sum = (sum & 0xFFFF) + ((sum >> 16) & 0xFFFF); + return sum ^ 0xFFFF; +} + +void IPIn(IPInterface* interface, IPHeader* ip, s32 len, u32 flag) { + BOOL bcast; + + bcast = IPIsBroadcastAddr(interface, ip->dst); + if (len < 20 || len < ip->len) { + return; + } + + if ((flag & 1) != 0 && !bcast) { + return; + } + + if ((flag & 2) != 0 && !IP_CLASSD(ip->dst)) { + return; + } + + if ((ip->verlen >> 4) != 4 || ip->len < IP_HLEN(ip)) { + return; + } + + if (IPCheckSum(ip) != 0) { + return; + } + + if (IP_CLASSD(ip->src) || (IPNEQ(ip->src, IPAddrAny) && IPIsBroadcastAddr(interface, ip->src))) { + return; + } + + if (IP_CLASSE(ip->dst) || IP_CLASSE(ip->src)) { + return; + } + + if (IPProcessSourceRoute(ip) < 0) { + return; + } + + if (IPNEQ(interface->addr, IPAddrAny) && !IP_CLASSD(ip->dst) && !bcast && ip->dst[0] != 127 && + IPNEQ(ip->dst, interface->addr) && IPNEQ(ip->dst, interface->alias)) { + return; + } + + if ((ip->frag & IP_HAS_FRAG) != 0 || IP_FRAG(ip) != 0) { + ip = IPReassemble(interface, ip, flag); + if (ip == NULL) { + return; + } + } + + switch (ip->proto) { + case IP_PROTO_ICMP: + ICMPIn(interface, ip, flag); + break; + case IP_PROTO_IGMP: + IGMPIn(interface, ip, flag); + break; + case IP_PROTO_UDP: + UDPIn(interface, ip, flag); + break; + case IP_PROTO_TCP: + if ((flag & 0x3) == 0) { + TCPIn(interface, ip, flag); + } + break; + } + + ip->verlen = 0; +} + +s32 IPOut(IFDatagram* datagram) { + IPHeader* ip; + IPInterface* interface; + TCPHeader* tcp; + UDPHeader* udp; + IGMP* igmp; + + ASSERT(0 < datagram->nVec && datagram->nVec <= IF_MAX_VEC); + ip = (IPHeader*)datagram->vec[0].data; + ASSERT(IP_HLEN(ip) <= datagram->vec[0].len); + + ip->id = Id++; + if (IP_CLASSD(ip->dst)) { + interface = &__IFDefault; + memmove(datagram->dst, ip->dst, sizeof(datagram->dst)); + } else { + interface = (IPInterface*)IPGetRoute(ip->dst, datagram->dst); + if (interface == NULL) { + return -2; + } + } + + if (interface->mtu < ip->len) { + return -17; + } + + if (ip->src[0] != 127 && IPNEQ(interface->addr, ip->src) && IPNEQ(interface->alias, ip->src)) { + return -19; + } + + + ip->sum = 0; + ip->sum = IPCheckSum(ip); + + switch (ip->proto) { + case IP_PROTO_IGMP: + igmp = (IGMP*)(((u8*)ip) + IP_HLEN(ip)); + igmp->sum = 0; + igmp->sum = IGMPCheckSum(igmp); + break; + case IP_PROTO_UDP: + udp = (UDPHeader*)(((u8*)ip) + IP_HLEN(ip)); + udp->sum = 0; + udp->sum = UDPCheckSum(datagram->vec, datagram->nVec); + if (udp->sum == 0) { + udp->sum = 0xFFFF; + } + break; + case IP_PROTO_TCP: + tcp = (TCPHeader*)(((u8*)ip) + IP_HLEN(ip)); + tcp->sum = 0; + tcp->sum = TCPCheckSum(datagram->vec, datagram->nVec); + ASSERT((tcp->flag & (TCP_FLAG_SYN | TCP_FLAG_FIN)) != (TCP_FLAG_SYN | TCP_FLAG_FIN)); + break; + } + + datagram->type = ETH_IP; + (*interface->out)(interface, datagram); + return 0; +} + +void IPCancel(IFDatagram* datagram) { + IPInterface* interface; + + interface = datagram->interface; + if (interface) { + (*interface->cancel)(interface, datagram); + ASSERT(datagram->interface == NULL); + } +} + +void IFInitDatagram(IFDatagram* datagram, u16 type, int nVec) { + datagram->interface = NULL; + datagram->queue = NULL; + datagram->type = type; + //datagram->offset = 0; + datagram->prefixLen = 0; + datagram->flag = 0; + datagram->callback = NULL; + datagram->param = NULL; + datagram->nVec = nVec; + memset(datagram->vec, 0, nVec * sizeof(IFVec)); +} diff --git a/libs/dolphin/ip/IPArp.c b/libs/dolphin/ip/IPArp.c index e69de29b..7f7d8218 100644 --- a/libs/dolphin/ip/IPArp.c +++ b/libs/dolphin/ip/IPArp.c @@ -0,0 +1,709 @@ +#include "dolphin/os.h" +#include +#include +#include +#include + +#ifdef NULL +#undef NULL +#endif + +#define NULL 0 +#define ARP_CACHE_SIZE 64 + +static ARPCache Cache[ARP_CACHE_SIZE]; // size: 0x2A00, address: 0x0 +static IFQueue Up; // size: 0x8, address: 0x0 +static IFQueue Free; // size: 0x8, address: 0x8 +static u8 HwBroadcastAddr[6] = { 255, 255, 255, 255, 255, 255 }; // size: 0x6, address: 0x0 +static OSAlarm GratuitousAlarm; // size: 0x28, address: 0x2A00 + +static void ARPCancel(ARPCache* cache); + +// Range: 0x0 -> 0xBC +static char* ARPNtoA(const u8* addr /* r1+0x8 */, s32 len /* r31 */) { + // Local variables + static char ascii[18]; + int i; // r30 + char* p; // r29 + + ASSERT(1 <= len); + len = len < 6 ? len : 6; + + for (i = 0, p = ascii; i < len; i++) { + p += sprintf(p, "%02x", addr[i]); + if (i < len - 1) { + p += sprintf(p, ":"); + } + } + + return ascii; +} + +// Range: 0xBC -> 0x2C4 +void ARPDumpPacket(const ETHHeader* eh /* r29 */, s32 len /* r28 */) { + // Local variables + ARPHeader* arp; // r31 + + arp = (ARPHeader*)(eh+1); + OSReport("%s ", ARPNtoA(eh->src, sizeof(eh->src))); + OSReport("%s ", ARPNtoA(eh->dst, sizeof(eh->dst))); + + switch (eh->type) { + case 0x0806: + OSReport("arp %d:\n", len); + break; + case 0x8035: + OSReport("rarp %d:\n", len); + break; + } + + switch (arp->opCode) { + case 1: + OSReport("arp who-has %s ", IPNtoA((u8*)arp + arp->hwAddrLen * sizeof(u16) + arp->prAddrLen + sizeof(ARPHeader))); + OSReport("tell %s\n", IPNtoA((u8*)arp + arp->hwAddrLen + sizeof(ARPHeader))); + break; + case 2: + OSReport("arp reply %s ", IPNtoA((u8*)arp + arp->hwAddrLen + sizeof(ARPHeader))); + OSReport("is-at %s\n", ARPNtoA((u8*)arp + sizeof(ARPHeader), arp->hwAddrLen)); + break; + case 3: + OSReport("rarp who-is %s ", ARPNtoA((u8*)arp + sizeof(ARPHeader), arp->hwAddrLen)); + OSReport("tell %s\n", ARPNtoA((u8*)arp + sizeof(ARPHeader), arp->hwAddrLen)); + break; + case 4: + OSReport("rarp reply %s ", ARPNtoA((u8*)arp + arp->hwAddrLen + arp->prAddrLen + sizeof(ARPHeader), arp->hwAddrLen)); + OSReport("at %s\n", IPNtoA((u8*)arp + arp->hwAddrLen * sizeof(u16) + arp->prAddrLen + sizeof(ARPHeader))); + break; + } +} + +// Range: 0x2C4 -> 0x47C +void ARPDump(void) { + // Local variables + ARPCache* ent; // r31 + ARPCache* next; // r29 + + // References + // -> static struct IFQueue Up; + // -> struct IPInterface __IFDefault; + // -> unsigned char IPAddrAny[4]; + + if (IPNEQ(__IFDefault.addr, IPAddrAny)) { + OSReport("Internet Address: %d.%d.%d.%d\n", __IFDefault.addr[0], __IFDefault.addr[1], __IFDefault.addr[2], __IFDefault.addr[3]); + } + + if (IPNEQ(__IFDefault.alias, IPAddrAny)) { + OSReport("Alias Address: %d.%d.%d.%d\n", __IFDefault.alias[0], __IFDefault.alias[1], __IFDefault.alias[2], __IFDefault.alias[3]); + } + + OSReport("Hardware Address: %02x:%02x:%02x:%02x:%02x:%02x\n", __IFDefault.mac[0], __IFDefault.mac[1], __IFDefault.mac[2], __IFDefault.mac[3], __IFDefault.mac[4], __IFDefault.mac[5]); + + OSReport(" Internet Address Hardware Address\n"); + IFQueueIterator(ARPCache*, &Up, ent, next) { + OSReport(" %3d.%3d.%3d.%3d %02x:%02x:%02x:%02x:%02x:%02x\n", ent->prAddr[0], ent->prAddr[1], ent->prAddr[2], ent->prAddr[3], ent->hwAddr[0], ent->hwAddr[1], ent->hwAddr[2], ent->hwAddr[3], ent->hwAddr[4], ent->hwAddr[5]); + } + + OSReport("\n"); +} + +// Range: 0x47C -> 0x560 +static void DiscardPendingPackets(ARPCache* cache /* r29 */, s32 result /* r1+0xC */) { + // Local variables + IPInterface* interface; // r28 + IFDatagram* datagram; // r31 + + interface = cache->interface; + while (cache->queue.next) { + IFQueueDequeueHead(IFDatagram*, &cache->queue, datagram); + ASSERT(datagram->queue == &cache->queue); + ASSERT(datagram->interface == interface); + datagram->interface = NULL; + datagram->queue = NULL; + if (datagram->callback) { + datagram->callback(datagram->param, result); + } + } + + (void)0; +} + +// Range: 0x560 -> 0x6B8 +static void Revalidate(ARPCache* cache /* r31 */) { + // Local variables + IPInterface* interface; // r27 + // struct IFQueue * ___next; // r30 + // struct IFQueue * ___prev; // r29 + // struct IFQueue * ___next; // r28 + + switch (cache->state) { + case 0: + default: + break; + case ARP_CACHE_RESOVLED: + cache->state = ARP_CACHE_POLLING; + cache->rxmit = 1; + // fallthrough + case 1: + case ARP_CACHE_POLLING: + interface = cache->interface; + ARPCancel(cache); + if (cache->rxmit < 32) { + cache->rxmit <<= 1; + ARPOut(interface, 1, cache->prAddr, cache->state == ARP_CACHE_POLLING ? cache->hwAddr : NULL, IPEQ(interface->addr, IPAddrAny) ? interface->alias : interface->addr, cache); + } else { + IPRecoverGateway(cache->prAddr); + IFQueueDequeueEntry(ARPCache*, &Up, cache); + OSCancelAlarm(&cache->alarm); + cache->state = 0; + IFQueueEnqueueHead(ARPCache*, &Free, cache); + DiscardPendingPackets(cache, -2); + } + break; + } + // References + // -> static struct IFQueue Free; + // -> static struct IFQueue Up; + // -> unsigned char IPAddrAny[4]; +} + +// // Range: 0x6B8 -> 0x6F0 +static void TimeoutCallback(OSAlarm* alarm /* r1+0x8 */, OSContext* context) { + // Local variables + ARPCache* cache; // r31 + + cache = (ARPCache*)((s32)alarm - offsetof(ARPCache, alarm)); + Revalidate(cache); +} + +// // Range: 0x6F0 -> 0x7CC +static void SendCallback(ARPCache* cache /* r31 */) { + ASSERT(cache->datagram.interface == NULL); + ASSERT(cache->datagram.queue == NULL); + + switch (cache->state) { + case 1: + case ARP_CACHE_POLLING: + OSCancelAlarm(&cache->alarm); + OSSetAlarm(&cache->alarm, OSSecondsToTicks((OSTime)cache->rxmit), TimeoutCallback); + break; + } +} + +// // Range: 0x7CC -> 0x878 +void ARPInit(void) { + // Local variables + ARPCache* ent; // r31 + // struct IFQueue * ___prev; // r30 + + memset(Cache, 0, sizeof(Cache)); + IFQueueInit(&Up); + IFQueueInit(&Free); + for (ent = &Cache[0]; ent < &Cache[ARP_CACHE_SIZE]; ent++) { + OSCreateAlarm(&ent->alarm); + IFQueueEnqueueTail(ARPCache*, &Free, ent); + } + + // References + // -> static struct ARPCache Cache[64]; + // -> static struct IFQueue Free; + // -> static struct IFQueue Up; +} + +// // Range: 0x878 -> 0x8F8 +static ARPCache* Lookup(u8* prAddr /* r3 */) { + // Local variables + ARPCache* ent; // r31 + ARPCache* next; // r30 + + IFQueueIterator(ARPCache*, &Up, ent, next) { + if (IPEQ(ent->prAddr, prAddr)) { + if (ent->state == ARP_CACHE_RESOVLED || ent->state == ARP_CACHE_POLLING) { + return ent; + } + } + } + + return NULL; + + // References + // -> static struct IFQueue Up; +} + +// // Range: 0x8F8 -> 0xA68 +s32 ARPLookup(IPInterface* interface /* r25 */, u8* prAddr /* r26 */, u8* hwAddr /* r27 */) { + // Local variables + ARPCache* ent; // r31 + // struct IFQueue * ___next; // r30 + // struct IFQueue * ___prev; // r29 + // struct IFQueue * ___next; // r28 + + if (IP_CLASSD(prAddr)) { + hwAddr[0] = 1; + hwAddr[1] = 0; + hwAddr[2] = 94; + hwAddr[3] = prAddr[1] & 0x7F; + hwAddr[4] = prAddr[2]; + hwAddr[5] = prAddr[3]; + return ARP_MULTICAST; + } + + if (IPIsBroadcastAddr(interface, prAddr)) { + memset(hwAddr, 0xFF, 6); + return ARP_BROADCAST; + } + + if (IPIsLoopbackAddr(interface, prAddr)) { + memmove(hwAddr, interface->mac, 6); + return ARP_LOOPBACK; + } + + ent = Lookup(prAddr); + if (ent) { + if (Up.next != &ent->link) { + IFQueueDequeueEntry(ARPCache*, &Up, ent); + IFQueueEnqueueHead(ARPCache*, &Up, ent); + } + + memmove(hwAddr, ent->hwAddr, 6); + return ARP_FOUND; + } + + return ARP_NOTFOUND; + + // References + // -> static struct IFQueue Up; +} + +// // Range: 0xA68 -> 0xAAC +void ARPRevalidate(u8* prAddr /* r1+0x8 */) { + // Local variables + ARPCache* ent; // r31 + + ent = Lookup(prAddr); + if (ent) { + Revalidate(ent); + } +} + +// // Range: 0xAAC -> 0xC60 +static ARPCache* ARPAlloc(u8* prAddr /* r25 */, BOOL alloc /* r1+0xC */) { + // Local variables + ARPCache* ent; // r30 + ARPCache* next; // r26 + ARPCache* free; // r31 + // struct IFQueue * ___next; // r29 + // struct IFQueue * ___prev; // r28 + // struct IFQueue * ___next; // r27 + + IFQueueIterator(ARPCache*, &Up, ent, next) { + if (IPEQ(ent->prAddr, prAddr)) { + return ent; + } + } + + if (!alloc) { + return NULL; + } + + if (Free.next != NULL) { + IFQueueDequeueHead(ARPCache*, &Free, free); + } else { + IFQueueDequeueTail(ARPCache*, &Up, free); + ARPCancel(free); + OSCancelAlarm(&free->alarm); + if (free->state == 1) { + DiscardPendingPackets(free, -7); + } + + ASSERT(IFIsEmptyQueue(&free->queue)); + } + + memset(free, 0, sizeof(ARPCache)); + IFQueueInit(&free->queue); + OSCreateAlarm(&free->alarm); + free->rxmit = 1; + memmove(free->prAddr, prAddr, sizeof(free->prAddr)); + IFQueueEnqueueHead(ARPCache*, &Up, free); + return free; + + // References + // -> static struct IFQueue Up; + // -> static struct IFQueue Free; +} + +// // Range: 0xC60 -> 0xD40 +void ARPAdd(IPInterface* interface /* r1+0x8 */, u8* prAddr /* r1+0xC */, u8* hwAddr /* r1+0x10 */) { + // Local variables + ARPCache* cache; // r31 + + cache = ARPAlloc(prAddr, TRUE); + if (cache) { + ASSERT(cache->state != ARP_CACHE_RESOVLED && cache->state != ARP_CACHE_POLLING); + cache->state = ARP_CACHE_RESOVLED; + cache->interface = interface; + cache->rxmit = 1200; + OSSetAlarm(&cache->alarm, OSSecondsToTicks((OSTime)cache->rxmit), TimeoutCallback); + memmove(cache->hwAddr, hwAddr, 6); + } +} + +// // Range: 0xD40 -> 0xF5C +void ARPHold(IPInterface* interface /* r29 */, struct IFDatagram * datagram /* r31 */) { + // Local variables + ARPCache* free; // r30 + int state; // r22 + void (* callback)(void *, long); // r24 + void* param; // r21 + int discard; // r25 + s32 nVec; // r27 + IFVec va[4]; // r1+0x10 + IFVec* vec; // r23 + // struct IFQueue * ___prev; // r28 + + ASSERT(datagram->interface == interface); + callback = datagram->callback; + param = datagram->param; + datagram->interface = NULL; + datagram->queue = NULL; + free = ARPAlloc(datagram->dst, TRUE); + ASSERT(free); + ASSERT(free->state != ARP_CACHE_RESOVLED && free->state != ARP_CACHE_POLLING); + state = free->state; + free->state = 1; + free->interface = interface; + nVec = datagram->nVec; + ASSERT(0 < nVec && nVec <= IF_MAX_VEC); + memmove(va, datagram->vec, nVec * sizeof(IFVec)); + + discard = 0; + while (nVec-- > 0) { + vec = &va[nVec]; + discard |= interface->free(interface, vec->data, vec->len); + } + + discard |= interface->free(interface, datagram, sizeof(IFDatagram) + (datagram->nVec > 1 ? (datagram->nVec - 1) * sizeof(IFVec) : 0)); + + if (discard == 0) { + datagram->interface = interface; + datagram->queue = &free->queue; + IFQueueEnqueueTail(IFDatagram*, &free->queue, datagram); + } else { + if (callback) { + (*callback)(param, -7); + } + } + + if (state == 0) { + ARPOut(interface, 1, free->prAddr, NULL, IPEQ(interface->addr, IPAddrAny) ? interface->alias : interface->addr, free); + } + // References + // -> unsigned char IPAddrAny[4]; +} + +// // Range: 0xF5C -> 0x11A4 +static void ARPUpdate(IPInterface* interface /* r27 */, ARPHeader* arp /* r29 */) { + // Local variables + ARPCache* cache; // r31 + int state; // r24 + u8* src; // r26 + IFDatagram* datagram; // r28 + // struct IFQueue * ___next; // r30 + + src = ARPHeader2PrAddr(arp); + if (IP_CLASSD(src) || IP_CLASSE(src) || IPEQ(src, IPAddrAny) || IPIsBroadcastAddr(interface, src)) { + return; + } + + cache = ARPAlloc(src, IPEQ(ARPHeader2Addr(arp), interface->addr) || IPEQ(ARPHeader2Addr(arp), interface->alias)); + if (cache != NULL) { + ARPCancel(cache); + OSCancelAlarm(&cache->alarm); + cache->rxmit = 1200; + OSSetAlarm(&cache->alarm, OSSecondsToTicks((OSTime)cache->rxmit), TimeoutCallback); + state = cache->state; + cache->state = ARP_CACHE_RESOVLED; + memmove(cache->hwAddr, ARPHeader2MACAddr(arp), 6); + if (cache->interface != interface) { + DiscardPendingPackets(cache, -2); + cache->interface = interface; + } + + if (state == 1) { + while (cache->queue.next) { + IFQueueDequeueHead(IFDatagram*, &cache->queue, datagram); + ASSERT(datagram->queue == &cache->queue); + ASSERT(datagram->type == ETH_IP); + ASSERT(ARPLookup(interface, datagram->dst, datagram->hwAddr) == ARP_FOUND); + datagram->queue = NULL; + interface->out(interface, datagram); + } + } + } + + // References + // -> unsigned char IPAddrAny[4]; +} + +// // Range: 0x11A4 -> 0x13C0 +void ARPOut(IPInterface* interface /* r29 */, u16 opCode /* r1+0xC */, const u8* dstPrAddr /* r1+0x10 */, const u8* dstHwAddr /* r27 */, const u8* srcPrAddr /* r25 */, ARPCache* cache /* r28 */) { + // Local variables + BOOL enabled; // r26 + IFDatagram* datagram; // r30 + ARPHeader* arp; // r31 + + enabled = OSDisableInterrupts(); + if (interface->out != ETHOut) { + OSRestoreInterrupts(enabled); + return; + } + + if (cache != NULL) { + datagram = &cache->datagram; + arp = (ARPHeader*)cache->arp; + ASSERT(datagram->queue == NULL); + } else { + datagram = (IFDatagram*)interface->alloc(interface, sizeof(IFDatagram) + sizeof(cache->arp)); + arp = (ARPHeader*)((s32)datagram + sizeof(IFDatagram)); + } + + if (datagram != NULL) { + arp->hwType = 1; + arp->prType = ETH_IP; + arp->hwAddrLen = 6; + arp->prAddrLen = 4; + arp->opCode = opCode; + memmove(ARPHeader2Addr(arp), dstPrAddr, 4); + + if (dstHwAddr) { + memmove(ArpHeader2HwAddr(arp), dstHwAddr, 6); + } else { + memset(ArpHeader2HwAddr(arp), 0, 6); + } + + memmove(ARPHeader2PrAddr(arp), srcPrAddr, 4); + memmove(ARPHeader2MACAddr(arp), interface->mac, 6); + + datagram->nVec = 1; + datagram->vec[0].data = arp; + datagram->vec[0].len = sizeof(cache->arp); + datagram->callback = cache ? (void (*)(void *, s32))SendCallback : NULL; + datagram->param = cache; + datagram->type = ETH_IP | 6; + datagram->flag = 0; + + if (dstHwAddr && (srcPrAddr[0] != 169 || srcPrAddr[1] != 254)) { + memmove(datagram->hwAddr, dstHwAddr, 6); + } else { + memmove(datagram->hwAddr, HwBroadcastAddr, 6); + } + + datagram->queue = NULL; + interface->out(interface, datagram); + } + + OSRestoreInterrupts(enabled); + // References + // -> static unsigned char HwBroadcastAddr[6]; +} + +// // Range: 0x13C0 -> 0x1410 +static void ARPCancel(ARPCache* cache /* r1+0x8 */) { + // Local variables + IFDatagram* datagram; // r30 + IPInterface* interface; // r31 + + datagram = &cache->datagram; + interface = datagram->interface; + if (interface != NULL) { + interface->cancel(interface, datagram); + } +} + +// // Range: 0x1410 -> 0x1498 +static void GratuitousCallback(OSAlarm* alarm /* r1+0x8 */, OSContext* context) { + // Local variables + IPInterface* interface; // r31 + + interface = (IPInterface*)((u8*)alarm - offsetof(IPInterface, gratuitousAlarm)); + if (IPNEQ(interface->addr, IPAddrAny)) { + ARPOut(interface, 1, interface->addr, NULL, interface->addr, NULL); + } + + if (IPNEQ(interface->alias, IPAddrAny)) { + ARPOut(interface, 1, interface->alias, NULL, interface->alias, NULL); + } + + // References + // -> unsigned char IPAddrAny[4]; +} + +// // Range: 0x1498 -> 0x1544 +void ARPGratuitous(IPInterface* interface /* r31 */) { + OSCancelAlarm(&interface->gratuitousAlarm); + OSSetAlarm(&interface->gratuitousAlarm, OSSecondsToTicks(3), GratuitousCallback); + + if (IPNEQ(interface->addr, IPAddrAny)) { + ARPOut(interface, 1, interface->addr, NULL, interface->addr, NULL); + } + + if (IPNEQ(interface->alias, IPAddrAny)) { + ARPOut(interface, 1, interface->alias, NULL, interface->alias, NULL); + } + + // References + // -> unsigned char IPAddrAny[4]; +} + +// // Range: 0x1544 -> 0x1584 +void ARPProbe(IPInterface* interface /* r1+0x8 */, u8* prAddr /* r1+0xC */) { + + ARPOut(interface, 1, prAddr, NULL, IPAddrAny, NULL); + // References + // -> unsigned char IPAddrAny[4]; +} + +// // Range: 0x1584 -> 0x1614 +static void ClaimHandler(OSAlarm* alarm /* r1+0x8 */, OSContext* context) { + // Local variables + IPInterfaceConf* conf; // r31 + IPInterface* interface; // r30 + + conf = (IPInterfaceConf*)((u8*)alarm - offsetof(IPInterfaceConf, alarm)); + interface = conf->interface; + + conf->count++; + if (conf->count <= 4) { + ARPProbe(interface, conf->addr); + OSSetAlarm(&conf->alarm, OSSecondsToTicks(2), ClaimHandler); + } else { + conf->callback(conf, 0); + } +} + +// // Range: 0x1614 -> 0x17CC +void ARPClaim(IPInterface* interface /* r27 */, IPInterfaceConf* conf /* r31 */) { + // Local variables + BOOL enabled; // r23 + OSTime wait; // r25 + OSTick r; // r24 + // struct IFQueue * ___prev; // r28 + // struct IFQueue * ___next; // r30 + // struct IFQueue * ___prev; // r29 + + ASSERT(interface); + enabled = OSDisableInterrupts(); + + if (IPNEQ(conf->addr, IPAddrAny)) { + ASSERT(conf->callback); + + if (conf->interface == NULL) { + conf->interface = interface; + IFQueueEnqueueTail(IPInterfaceConf*, &interface->queue, conf); + } + + OSCancelAlarm(&conf->alarm); + conf->count = 0; + wait = OSMillisecondsToTicks(1200); + r = OSGetTick(); + r %= OSMillisecondsToTicks(1600); + wait = (wait + r) - OSMillisecondsToTicks(800); + OSSetAlarm(&conf->alarm, wait, ClaimHandler); + } else if (conf->interface == interface) { + OSCancelAlarm(&conf->alarm); + IFQueueDequeueEntry(IPInterfaceConf*, &interface->queue, conf); + conf->interface = NULL; + } + + OSRestoreInterrupts(enabled); + + // References + // -> unsigned char IPAddrAny[4]; +} + +// // Range: 0x17CC -> 0x1978 +static BOOL DetectCollision(IPInterface* interface /* r29 */, ARPHeader* arp /* r30 */) { + // Local variables + IPInterfaceConf* conf; // r31 + IPInterfaceConf* next; // r28 + + IFQueueIterator(IPInterfaceConf*, &interface->queue, conf, next) { + if ( + IPNEQ(IPAddrAny, conf->addr) && (IPEQ(ARPHeader2PrAddr(arp), conf->addr) && memcmp(ARPHeader2MACAddr(arp), interface->mac, 6) != 0 || + (IPEQ(ARPHeader2Addr(arp), conf->addr) && IPEQ(ARPHeader2PrAddr(arp), IPAddrAny))) + ) { + OSCancelAlarm(&conf->alarm); + + if (conf->callback) { + conf->callback(conf, -111); + } + } + } + + if (IPNEQ(IPAddrAny, interface->addr) && IPEQ(ARPHeader2PrAddr(arp), interface->addr) && memcmp(ARPHeader2MACAddr(arp), interface->mac, 6) != 0) { + IPSetConfigError(interface, -111); + return TRUE; + } else if (IPNEQ(IPAddrAny, interface->alias) && IPEQ(ARPHeader2PrAddr(arp), interface->alias) && memcmp(ARPHeader2MACAddr(arp), interface->mac, 6) != 0) { + IPAutoConfig(); + return TRUE; + } + + return FALSE; + + // References + // -> unsigned char IPAddrAny[4]; +} + +// // Range: 0x1978 -> 0x1AEC +void ARPIn(IPInterface* interface /* r30 */, ETHHeader* eh /* r1+0xC */, s32 len /* r29 */) { + // Local variables + ARPHeader* arp; // r31 + + arp = (ARPHeader*)(eh+1); + if (interface->out != ETHOut || len < 22 || len < (2 * (arp->hwAddrLen + arp->prAddrLen) + 22)) { + return; + } + + if (arp->hwType != 1 || arp->prType != ETH_IP || arp->hwAddrLen != 6 || arp->prAddrLen != 4) { + return; + } + + DetectCollision(interface, arp); + ARPUpdate(interface, arp); + + if (IPEQ(ARPHeader2Addr(arp), IPAddrAny) || + ((IPNEQ(ARPHeader2Addr(arp), interface->addr) && IPNEQ(ARPHeader2Addr(arp), interface->alias)))) { + return; + } + + if (arp->opCode == 1) { + ARPOut(interface, 2, ARPHeader2PrAddr(arp), ARPHeader2MACAddr(arp), ARPHeader2Addr(arp), NULL); + } + // References + // -> unsigned char IPAddrAny[4]; +} + +// // Range: 0x1AEC -> 0x1BAC +void ARPRefresh(void) { + // Local variables + ARPCache* cache; // r31 + BOOL enabled; // r28 + // struct IFQueue * ___next; // r30 + // struct IFQueue * ___next; // r29 + + enabled = OSDisableInterrupts(); + + while (Up.next) { + IFQueueDequeueHead(ARPCache*, &Up, cache); + ARPCancel(cache); + OSCancelAlarm(&cache->alarm); + cache->state = 0; + IFQueueEnqueueHead(ARPCache*, &Free, cache); + DiscardPendingPackets(cache, 0); + } + + OSRestoreInterrupts(enabled); + + // References + // -> static struct IFQueue Up; + // -> static struct IFQueue Free; +} diff --git a/libs/dolphin/ip/IPSocket.c b/libs/dolphin/ip/IPSocket.c index e69de29b..04ad2dcd 100644 --- a/libs/dolphin/ip/IPSocket.c +++ b/libs/dolphin/ip/IPSocket.c @@ -0,0 +1,1207 @@ +#include "dolphin/ip.h" +#include "dolphin/ip/IPDhcp.h" +#include "dolphin/ip/IPUdp.h" +#include "dolphin/os.h" +#include "dolphin/os/OSContext.h" +#include + +#include +#include +#include + +static SOAllocFunc Alloc = NULL; +static SOFreeFunc Free = NULL; +static u32 Allocated = 0; + +#define SO_TABLE_NUM 256 +static SONode SocketTable[SO_TABLE_NUM]; +static IFQueue LingerQueue; +static SOSockAddrIn SockAnyIn = { 8, 2, 0, { 0 } }; +static u8* TimeWaitBuf = NULL; +static s32 TimeWaitBufSize = 0; +static u8* ReassemblyBuffer = NULL; +static s32 ReassemblyBufferSize = 0; +static s32 State = 0; +static u32 Flag = 0; +static s32 Mtu = 0; +static s32 Rwin = 0; +static OSTime R2 = 0; + +static OSThreadQueue CleaningQueue; +static OSThreadQueue PollingQueue; +static BOOL LowInitialized; +static BOOL Initialized; + +static BOOL OnReset(BOOL); +static OSResetFunctionInfo ResetFunctionInfo = { &OnReset, 110, NULL, NULL }; + +static void LingerCallback(TCPInfo* info, s32); + +void* SOAlloc(u32 name, s32 size) { + void* ptr; + BOOL enabled; + + ASSERT(Alloc); + + ptr = (*Alloc)(name, size); + if (ptr != NULL) { + enabled = OSDisableInterrupts(); + Allocated += size; + OSRestoreInterrupts(enabled); + } + + return ptr; +} + +void SOFree(u32 name, void* ptr, s32 size) { + BOOL enabled; + + ASSERT(Free); + + if (ptr != NULL) { + (*Free)(name, ptr, size); + enabled = OSDisableInterrupts(); + Allocated -= size; + + if (Allocated == 0 && State == 2) { + OSWakeupThread(&CleaningQueue); + } + + OSRestoreInterrupts(enabled); + } +} + +u32 SONtoHl(u32 netlong) { + return netlong; +} + +u16 SONtoHs(u16 netshort) { + return netshort; +} + +u32 SOHtoNl(u32 hostlong) { + return hostlong; +} + +u16 SOHtoNs(u16 hostshort) { + return hostshort; +} + +int SOInetAtoN(const char* cp, SOInAddr* inp) { + u8 addr[4]; + + if (IPAtoN(cp, inp != NULL ? (u8*)&inp->addr : addr) != NULL) { + return TRUE; + } + + return FALSE; +} + +char* SOInetNtoA(SOInAddr in) { + return IPNtoA((u8*)&in); +} + +int SOInetPtoN(int af, const char* src, void* dst) { + if (af == 2) { + if (IPAtoN(src, (u8*)dst)) { + return TRUE; + } + + return FALSE; + } + + return -5; +} + +char* SOInetNtoP(int af, void* src, char* dst, u32 len) { + const u8* addr; + + if (af == 2 && dst != NULL && len >= 16) { + addr = (const u8*)src; + sprintf(dst, "%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3]); + return dst; + } + + return NULL; +} + +static struct SONode* GetNode(int s, IPInfo** pinfo) { + SONode* node; + IPInfo* info; + IPInfo* next; + TCPInfo* tcp; + BOOL enabled; + IFQueue queue; + + queue.next = queue.prev = NULL; + enabled = OSDisableInterrupts(); + + /* Find any TCP packets which are unused */ + IFQueueIterator(IPInfo*, &LingerQueue, info, next) { + tcp = (TCPInfo*)info; + if (tcp->node == NULL || ((SONode*)tcp->node)->ref == 0) { + IFQueueDequeueEntry(IPInfo*, &LingerQueue, info); + IFQueueEnqueueTail(IPInfo*, &queue, info); + } + } + + OSRestoreInterrupts(enabled); + + /* Free all unused TCP packets */ + while (queue.next != NULL) { + IFQueueDequeueHead(IPInfo*, &queue, info); + + tcp = (TCPInfo*)info; + SOFree(2, tcp->recvData, tcp->recvBuff); + SOFree(1, tcp->sendData, tcp->sendBuff); + SOFree(0, tcp, sizeof(TCPInfo)); + } + + node = NULL; + enabled = OSDisableInterrupts(); + if (s >= 0 && s < SO_TABLE_NUM) { + node = &SocketTable[s]; + if (node->ref <= 0 || node->info == NULL) { + node = NULL; + } else { + node->ref++; + if (pinfo != NULL) { + *pinfo = node->info; + } + } + } + OSRestoreInterrupts(enabled); + return node; +} + +static void PutNode(SONode* node) { + BOOL enabled; + IPInfo* info; + TCPInfo* tcp; + UDPInfo* udp; + u8 proto; + + ASSERT(node); + + proto = 0; + info = NULL; + enabled = OSDisableInterrupts(); + ASSERT(0 < node->ref); + if (--node->ref == 0 && node->info != NULL) { + info = node->info; + node->info = NULL; + proto = node->proto; + node->proto = 0; + } + OSRestoreInterrupts(enabled); + + if (info != NULL) { + switch (proto) { + case IP_PROTO_UDP: + udp = (UDPInfo*)info; + SOFree(5, udp->recvRing, udp->recvBuff); + SOFree(4, udp->sendData, udp->sendBuff); + SOFree(3, udp, sizeof(UDPInfo)); + break; + case IP_PROTO_TCP: + tcp = (TCPInfo*)info; + SOFree(2, tcp->recvData, tcp->recvBuff); + SOFree(1, tcp->sendData, tcp->sendBuff); + SOFree(0, tcp, sizeof(TCPInfo)); + break; + default: + OSHaltLine(540, "PutNode: unknown proto"); + break; + } + } +} + +static SOResolver Resolver; + +int SOSetResolver(const SOInAddr* dns1, const SOInAddr* dns2) { + if (State != 1) { + return -39; + } + + memmove(Resolver.dns1, dns1 ? dns1 : (const SOInAddr*)&IPAddrAny, sizeof(Resolver.dns1)); + memmove(Resolver.dns2, dns2 ? dns2 : (const SOInAddr*)&IPAddrAny, sizeof(Resolver.dns2)); + + DNSClose(&Resolver.info); + + if (*(u32*)Resolver.dns1 != *(u32*)IPAddrAny) { + DNSOpen(&Resolver.info, Resolver.dns1); + } + else if (*(u32*)Resolver.dns2 != *(u32*)IPAddrAny) { + DNSOpen(&Resolver.info, Resolver.dns2); + } + + Resolver.info.flag |= 0x4; + return 0; +} + +int SOGetResolver(SOInAddr* dns1, SOInAddr* dns2) { + BOOL enabled; + int rc; + + enabled = OSDisableInterrupts(); + if (State != 1) { + rc = -39; + } else { + if (dns1 != NULL) { + memcpy(dns1, Resolver.dns1, sizeof(Resolver.dns1)); + } + + if (dns2 != NULL) { + memcpy(dns2, Resolver.dns2, sizeof(Resolver.dns2)); + } + + rc = 0; + } + OSRestoreInterrupts(enabled); + return rc; +} + +static void LcpHandler(PPPConf* conf) { + if (conf->state == 0 && State == 2) { + OSWakeupThread(&CleaningQueue); + } +} + +static void DhcpHandler(int state) { + DHCPInfo info; + u8 prev1[4]; + u8 prev2[4]; + + switch (state) { + case 3: + DHCPGetStatus(&info); + if (SOGetResolver((SOInAddr*)prev1, (SOInAddr*)prev2) == 0) { + if (IPEQ(prev1, IPAddrAny) && IPEQ(prev2, IPAddrAny)) { + //DHCPGetOpt(DHCP_OPT_DNS, dns, sizeof(dns)); + SOSetResolver((SOInAddr*)info.dns1, (SOInAddr*)info.dns2); + } else { + SOSetResolver((SOInAddr*)prev1, (SOInAddr*)prev2); + } + } + break; + case 0: + IPSetMtu(0, Mtu); + if (State == 2) { + OSWakeupThread(&CleaningQueue); + } + break; + } +} + +void SOInit(void) { + if (!Initialized) { + Initialized = TRUE; + OSRegisterResetFunction(&ResetFunctionInfo); + } + + IFInit(4); + if (State == 0) { + if (SOGetHostID() != 0u || DHCPGetStatus(0) != 0) { + LowInitialized = TRUE; + } else { + IFMute(TRUE); + } + } +} + +int SOStartup(const SOConfig* config) { + SOHostEnt* ent = &Resolver.ent; + s32 mtu; + + if (config->vendor == 0 && config->version == 0x0100) { + if (!IFInit(4)) { + return -28; + } + + if (State != 0) { + return -28; + } + + if (config->mtu > 0) { + if (SO_GET_CONFIG_MTU(config) < 68) { + mtu = 68; + } else if (config->mtu >= SO_MTU_MAX) { + mtu = SO_MTU_MAX; + } else { + mtu = config->mtu; + } + } else { + mtu = SO_MTU_MAX; + } + + Mtu = mtu; + IPSetMtu(0, mtu); + + if (config->rwin > 0) { + Rwin = config->rwin < 28 ? 28 : config->rwin; + } else { + Rwin = 0; + } + + if (config->r2 > 0) { + R2 = config->r2; + } else { + R2 = OSSecondsToTicks(100); // default timeout is 100 seconds + } + + OSInitThreadQueue(&CleaningQueue); + OSInitThreadQueue(&PollingQueue); + + Alloc = config->alloc; + Free = config->free; + Flag = config->flag; + + if (!LowInitialized) { + if (config->timeWaitBuffer != 0) { + TimeWaitBufSize = config->timeWaitBuffer; + TimeWaitBuf = SOAlloc(6, TimeWaitBufSize); + TCPSetTimeWaitBuffer(TimeWaitBuf, TimeWaitBufSize); + } + + if (config->reassemblyBuffer != 0) { + ReassemblyBufferSize = config->reassemblyBuffer; + ReassemblyBuffer = SOAlloc(7, ReassemblyBufferSize); + //IPSetReassemblyBuffer(ReassemblyBuffer, ReassemblyBufferSize, UdpSendBuff); + } + + IPClearConfigError(0); + } + + if (!LowInitialized) { + if ((Flag & 2) != 0) { + Flag &= ~0x8001; + if (PPPInit(&__IFDefault, &PPPLcpConf, &PPPIpcpConf, config->peerid, config->passwd) == 0) { + goto fail; + } + PPPLcpConf.callback = &LcpHandler; + } else if ((Flag & 1) != 0) { + if (DHCPStartupEx(&DhcpHandler, config->rdhcp) == 0) { + LowInitialized = TRUE; + } + + DHCPAuto(0); + } else { + if (config->addr.addr != 0) { + if (SOGetHostID() == 0u) { + IPInitRoute(&config->addr, &config->netmask, &config->router); + } else { + LowInitialized = TRUE; + } + } + } + } + + if (!LowInitialized) { + ARPRefresh(); + } + + if ((Flag & 0x8000) != 0) { + IPAutoConfig(); + } + + LingerQueue.next = LingerQueue.prev = NULL; + memset(&Resolver, 0, sizeof(Resolver)); + Resolver.zero = NULL; + ent->name = Resolver.name; + ent->aliases = &Resolver.zero; + ent->addrType = 2; + ent->length = 4; + ent->addrList = Resolver.ptrList; + SOSetResolver(&config->dns1, &config->dns2); + State = 1; + return 0; + } + +fail: + if (TimeWaitBuf != NULL) { + SOFree(6, TimeWaitBuf, TimeWaitBufSize); + } + + if (ReassemblyBuffer != NULL) { + SOFree(7, ReassemblyBuffer, ReassemblyBufferSize); + } + + return -28; +} + +int SOCleanup(void) { + int s; + SONode* node; + IPInfo* info; + IPInfo* next; + SOLinger linger; + int optlen; + BOOL enabled; + TCPInfo* tcp; + + if (State != 1) { + return -27; + } + + State = 2; + __IPWakeupPollingThreads(); + + for (s = 0; s < SO_TABLE_NUM; s++) { + node = &SocketTable[s]; + + if (node->ref != 0) { + switch (node->proto) { + case IP_PROTO_UDP: + __SOClose(s); + break; + case IP_PROTO_TCP: + optlen = 8; + linger.onoff = 1; + linger.linger = 0; + __SOSetSockOpt(s, 0xFFFF, 0x80, &linger, optlen); + __SOClose(s); + break; + } + } + + IFQueueIterator(IPInfo*, &TCPInfoQueue, info, next) { + tcp = (TCPInfo*)info; + + if (tcp->closeCallback == &LingerCallback) { + TCPCancel(tcp); + } + } + + GetNode(-1, NULL); + + if ((Flag & 0x8000) != 0) { + IPAutoStop(); + } + + DNSClose(&Resolver.info); + + if (!LowInitialized) { + if ((Flag & 2) != 0) { + PPPClose(&PPPIpcpConf); + enabled = OSDisableInterrupts(); + while (PPPGetState(&PPPLcpConf) != 0) { + OSSleepThread(&CleaningQueue); + } + OSRestoreInterrupts(enabled); + } else if ((Flag & 1) != 0) { + enabled = OSDisableInterrupts(); + DHCPCleanup(); + while (DHCPGetStatus(0) != 0) { + OSSleepThread(&CleaningQueue); + } + OSRestoreInterrupts(enabled); + } else { + IPInitRoute(0, 0, 0); + IPSetBroadcastAddr(&__IFDefault, 0); + } + } + + if (TimeWaitBuf != NULL) { + SOFree(6, TimeWaitBuf, TimeWaitBufSize); + } + + if (ReassemblyBuffer != NULL) { + //IPSetReassemblyBuffer(NULL, 0, UdpSendBuff + 20); + SOFree(7, ReassemblyBuffer, ReassemblyBufferSize); + } + + enabled = OSDisableInterrupts(); + while (Allocated != 0) { + OSSleepThread(&CleaningQueue); + } + OSRestoreInterrupts(enabled); + ASSERT(Allocated == 0); + + if (!LowInitialized) { + IFMute(TRUE); + ARPRefresh(); + } + + State = 0; + return 0; + } +} + +static s32 GetRwin(void) { + s32 mtu; + + if (Rwin != 0) { + return Rwin; + } + + IPGetMtu(0, &mtu); + return (mtu - 40) * 2; +} + +int SOSocket(int af, int type, int protocol) { + BOOL enabled; + int socket; + SONode* node; + s32 rc; + TCPInfo* tcp; + UDPInfo* udp; + void* sendbuf; + void* recvbuf; + s32 rwin; + + tcp = NULL; + udp = NULL; + + if (State != 1) { + return -39; + } + + if (af != 2) { + return -5; + } + + if (protocol != 0) { + return -68; + } + + GetNode(-1, NULL); + node = NULL; + enabled = OSDisableInterrupts(); + for (socket = 0; socket < SO_TABLE_NUM; socket++) { + node = &SocketTable[socket]; + if (node->ref == 0) { + ASSERT(node->info == NULL); + node->ref = 2; + break; + } + } + OSRestoreInterrupts(enabled); + + if (node == NULL) { + return -33; + } + + rwin = GetRwin(); + switch (type) { + case 1: + tcp = SOAlloc(0, sizeof(TCPInfo)); + sendbuf = SOAlloc(1, rwin); + recvbuf = SOAlloc(2, rwin); + rc = TCPOpen(tcp, sendbuf, rwin, recvbuf, rwin); + if (rc >= 0) { + TCPSetTimeout(tcp, R2); + } + break; + case 2: + udp = SOAlloc(3, sizeof(UDPInfo)); + sendbuf = SOAlloc(4, 0x5b2); + recvbuf = SOAlloc(5, 0x1000); + rc = UDPOpen(udp, recvbuf, 0x1000); + if (rc >= 0) { + rc = UDPSetSendBuff(udp, sendbuf, 1458); + } + break; + default: + PutNode(node); + PutNode(node); + return -69; + } + + if (rc < 0) { + switch (type) { + case 1: + SOFree(0, tcp, sizeof(TCPInfo)); + SOFree(1, sendbuf, rwin); + SOFree(2, recvbuf, rwin); + break; + case 2: + SOFree(3, udp, sizeof(UDPInfo)); + SOFree(4, sendbuf, 0x5b2); + SOFree(5, recvbuf, 0x1000); + break; + } + + PutNode(node); + PutNode(node); + return -49; + } + + node->flag = 0; + OSInitMutex(&node->mutexRead); + OSInitMutex(&node->mutexWrite); + + switch (type) { + case 1: + tcp->node = node; + node->proto = IP_PROTO_TCP; + node->info = &tcp->pair; + break; + case 2: + node->proto = IP_PROTO_UDP; + node->info = &udp->pair; + break; + } + + PutNode(node); + return socket; +} + +static void LingerCallback(TCPInfo* info, s32) { + SONode* node; + + node = (SONode*)info->node; + if (node != NULL) { + ASSERT(0 < node->ref); + node->ref--; + } + + IFQueueEnqueueTail(IPInfo*, &LingerQueue, &info->pair); +} + +static void LingerTimeout(OSAlarm* alarm, OSContext*) { + TCPInfo* tcp; + + tcp = (TCPInfo*)(((u8*)alarm) - offsetof(TCPInfo, lingerAlarm)); + TCPCancel(tcp); +} + +static int __SOClose(int s) { + SONode* node; + IPInfo* info; + TCPInfo* tcp; + TCPInfo* log; + UDPInfo* udp; + SOLinger linger; + int optlen; + BOOL enabled; + s32 rc; + IFQueue queue; + + node = GetNode(s, &info); + if (node == NULL || info == NULL) { + return -8; + } + + ASSERT(0 < node->ref); + switch (node->proto) { + case IP_PROTO_UDP: + rc = UDPClose(info); + ASSERT(0 <= rc); + node->ref--; + break; + case IP_PROTO_TCP: + tcp = (TCPInfo*)info; + optlen = 8; + rc = TCPGetSockOpt(tcp, 0xFFFF, 0x80, &linger, &optlen); + ASSERT(0 <= rc); + + queue.next = queue.prev = NULL; + enabled = OSDisableInterrupts(); + + while (tcp->queueBacklog.next != NULL) { + IFQueueDequeueHeadLINK(TCPInfo*, &tcp->queueBacklog, linkLog, log); + log->logging = NULL; + TCPCancel(log); + IFQueueEnqueueTailLINK(TCPInfo*, &queue, linkLog, log); + } + + while (tcp->queueCompleted.next != NULL) { + IFQueueDequeueHeadLINK(TCPInfo*, &tcp->queueCompleted, linkLog, log); + log->logging = NULL; + TCPCancel(log); + IFQueueEnqueueTailLINK(TCPInfo*, &queue, linkLog, log); + } + + if (TCPGetStatus(tcp) == TCP_STATE_LISTEN) { + rc = TCPCancel(tcp); + ASSERT(TCPGetStatus(tcp) != TCP_STATE_LISTEN); + if (tcp->accepting > 0) { + OSWakeupThread(&tcp->queueThread); + } + node->ref--; + } else if ((node->flag & 0x4) != 0) { + rc = TCPCancel(tcp); + node->ref--; + } else if (linger.onoff) { + if (linger.linger <= 0) { + rc = TCPCancel(tcp); + } else { + OSSetAlarm(&tcp->lingerAlarm, OSSecondsToTicks(linger.linger), &LingerTimeout); + rc = TCPClose(tcp); + } + + node->ref--; + } else { + OSSetAlarm(&tcp->lingerAlarm, OSSecondsToTicks(15), &LingerTimeout); + rc = TCPCloseAsync(tcp, &LingerCallback, 0); + if (node->ref == 2) { + tcp->node = NULL; + node->ref--; + } + node->info = NULL; + } + + OSRestoreInterrupts(enabled); + + while (queue.next != NULL) { + IFQueueDequeueHeadLINK(TCPInfo*, &queue, linkLog, log); + SOFree(2, log->recvData, log->recvBuff); + SOFree(1, log->sendData, log->sendBuff); + SOFree(0, log, sizeof(TCPInfo)); + } + + ASSERT(0 <= rc); + break; + default: + rc = -8; + break; + } + + PutNode(node); + + if (rc < 0) { + return -8; + } + + return 0; +} + +int SOClose(int s) { + if (State != 1) { + return -39; + } + + return __SOClose(s); +} + +static void AcceptCallback(TCPInfo* tcp, s32 result) { + TCPInfo* logging; + + logging = tcp->logging; + if (logging != NULL) { + if (result >= 0) { + IFQueueDequeueEntryLINK(TCPInfo*, &logging->queueBacklog, linkLog, tcp); + IFQueueEnqueueTailLINK(TCPInfo*, &logging->queueCompleted, linkLog, tcp); + OSWakeupThread(&logging->queueThread); + if (logging->pair.poll > 0) { + __IPWakeupPollingThreads(); + } + } else { + IFQueueDequeueEntryLINK(TCPInfo*, &logging->queueBacklog, linkLog, tcp); + TCPCancel(tcp); + TCPOpen(tcp, tcp->sendData, tcp->sendBuff, tcp->recvData, tcp->recvBuff); + TCPSetTimeout(tcp, R2); + tcp->logging = logging; + IFQueueEnqueueTailLINK(TCPInfo*, &logging->queueBacklog, linkLog, tcp); + TCPAcceptAsync(tcp, logging, &AcceptCallback, 0); + } + } +} + +static TCPInfo* AddBackLog(TCPInfo* listening) { + TCPInfo* tcp; + void* sendbuf; + s32 sendbufLen; + void* recvbuf; + s32 recvbufLen; + s32 rc; + BOOL enabled; + + ASSERT(listening); + tcp = SOAlloc(0, sizeof(TCPInfo)); + sendbufLen = listening->sendBuff; + recvbufLen = listening->recvBuff; + sendbuf = SOAlloc(1, sendbufLen); + recvbuf = SOAlloc(2, recvbufLen); + rc = TCPOpen(tcp, sendbuf, sendbufLen, recvbuf, recvbufLen); + if (rc >= 0) { + TCPSetTimeout(tcp, R2); + enabled = OSDisableInterrupts(); + + if (TCPGetStatus(listening) == TCP_STATE_LISTEN) { + tcp->logging = listening; + IFQueueEnqueueTailLINK(TCPInfo*, &listening->queueBacklog, linkLog, tcp); + OSRestoreInterrupts(enabled); + TCPAcceptAsync(tcp, listening, &AcceptCallback, 0); + OSRestoreInterrupts(enabled); + return tcp; + } + + OSRestoreInterrupts(enabled); + } + + SOFree(2, recvbuf, recvbufLen); + SOFree(1, sendbuf, sendbufLen); + SOFree(0, tcp, sizeof(TCPInfo)); + return NULL; +} + +int SOListen(int s, int backlog) { + SONode* node; + IPInfo* info; + TCPInfo* listening; + s32 rc; + + if (State != 1) { + return -39; + } + + if (backlog < 1) { + backlog = 1; + } + + node = GetNode(s, &info); + if (node == NULL || info == NULL) { + return -8; + } + + switch (info->proto) { + case IP_PROTO_UDP: + rc = -63; + break; + case IP_PROTO_TCP: + listening = (TCPInfo*)info; + rc = TCPListen(listening, NULL, NULL, NULL, 0); + switch (rc) { + case 0: + while (backlog-- > 0) { + if (AddBackLog(listening) == NULL) { + break; + } + } + break; + case -7: + rc = -42; + break; + case -5: + default: + rc = -28; + break; + } + break; + default: + rc = -8; + break; + } + + PutNode(node); + return rc; +} + +int SOAccept(int s, void* sockAddr) { + BOOL enabled; + SONode* node; + IPInfo* info; + TCPInfo* listening; + TCPInfo* tcp; + int socket; + s32 rc; + s32 state; + SONode* connected; + + if (State != 1) { + return -39; + } + + if (sockAddr && sizeof(SOSockAddrIn) > ((SOSockAddr*) sockAddr)->len) { + return -28; + } + + node = GetNode(s, &info); + if (node == NULL || info == NULL) { + return -8; + } + + enabled = OSDisableInterrupts(); + switch (info->proto) { + case IP_PROTO_UDP: + rc = -63; + break; + case IP_PROTO_TCP: + listening = (TCPInfo*)info; + + tcp_accept_loop: + if (TCPGetStatus(listening) != TCP_STATE_LISTEN) { + rc = -28; + break; + } + + listening->accepting++; + while (TCPGetStatus(listening) == TCP_STATE_LISTEN && listening->queueCompleted.next == NULL) { + if ((node->flag & 0x4) != 0) { + listening->accepting--; + rc = -6; + goto func_exit; + } + + OSSleepThread(&listening->queueThread); + } + + listening->accepting--; + if (TCPGetStatus(listening) != TCP_STATE_LISTEN) { + rc = -13; + break; + } + + for (socket = 0; socket < SO_TABLE_NUM; socket++) { + connected = &SocketTable[socket]; + if (connected->ref == 0) { + IFQueueDequeueHeadLINK(TCPInfo*, &listening->queueCompleted, linkLog, tcp); + ASSERT(tcp); + rc = 0; + if (sockAddr != NULL) { + rc = TCPGetRemoteSocket(tcp, (IPSocket*)sockAddr); + + } + + state = TCPGetStatus(tcp); + if ((state != 4 && state != 7) || rc < 0) { + TCPCancel(tcp); + TCPOpen(tcp, tcp->sendData, tcp->sendBuff, tcp->recvData, tcp->recvBuff); + TCPSetTimeout(tcp, R2); + tcp->logging = listening; + IFQueueEnqueueTailLINK(TCPInfo*, &listening->queueBacklog, linkLog, tcp); + TCPAcceptAsync(tcp, listening, &AcceptCallback, 0); + goto tcp_accept_loop; + } else { + connected->flag = node->flag; + connected->ref = 1; + OSInitMutex(&connected->mutexRead); + OSInitMutex(&connected->mutexWrite); + connected->proto = IP_PROTO_TCP; + connected->info = &tcp->pair; + rc = socket; + OSRestoreInterrupts(enabled); + AddBackLog(listening); + break; + } + } + } + + if (socket >= SO_TABLE_NUM) { + rc = -33; + } + break; + default: + rc = -8; + break; + } + +func_exit: + OSRestoreInterrupts(enabled); + PutNode(node); + return rc; +} + +int SOBind(int s, void* sockAddr) { + SONode* node; + IPInfo* info; + TCPInfo* tcp; + UDPInfo* udp; + s32 rc; + + if (State != 1) { + return -39; + } + + ASSERT(sockAddr == NULL || sizeof(SOSockAddrIn) <= ((SOSockAddr*) sockAddr)->len); + if (sockAddr == NULL || sizeof(SOSockAddrIn) > ((SOSockAddr*) sockAddr)->len) { + return -28; + } + + node = GetNode(s, &info); + if (node == NULL || info == NULL) { + return -8; + } + + switch (info->proto) { + case IP_PROTO_UDP: + udp = (UDPInfo*)info; + rc = UDPBind(udp, (IPSocket*)sockAddr); + break; + case IP_PROTO_TCP: + tcp = (TCPInfo*)info; + rc = TCPBind(tcp, (IPSocket*)sockAddr); + break; + default: + PutNode(node); + return -8; + } + + PutNode(node); + switch (rc) { + case 0: + return 0; + case -13: + return -5; + case -5: + return -3; + case -12: + default: + return -28; + } +} + +int SOConnect(int s, void* sockAddr) { + SONode* node; + IPInfo* info; + TCPInfo* tcp; + UDPInfo* udp; + s32 rc; + + if (State != 1) { + return -39; + } + + ASSERT(sockAddr == NULL || sizeof(SOSockAddrIn) <= ((SOSockAddr*) sockAddr)->len); + if (sockAddr == NULL || sizeof(SOSockAddrIn) <= ((SOSockAddr*) sockAddr)->len) { + return -28; + } + + node = GetNode(s, &info); + if (node == NULL || info == NULL) { + return -8; + } + + switch (info->proto) { + case IP_PROTO_UDP: + udp = (UDPInfo*)info; + if (((SOSockAddr*) sockAddr)->family == 0) { + sockAddr = &SockAnyIn; + } + rc = UDPConnect(udp, (IPSocket*)sockAddr); + break; + case IP_PROTO_TCP: + tcp = (TCPInfo*)info; + if ((node->flag & 0x4) == 0) { + rc = TCPConnect(tcp, (IPSocket*)sockAddr); + } else { + rc = TCPConnectAsync(tcp, (IPSocket*)sockAddr, NULL, 0); + if (rc == 0 && tcp->openCallback != NULL) { + rc = -1; + } + } + break; + default: + PutNode(node); + return -8; + } + + PutNode(node); + switch (rc) { + case 0: + return 0; + case -1: + return -26; + case -13: + return -5; + case -5: + return -30; + case -3: + return -15; + case -11: + return -14; + case -10: + return -76; + case -12: + return -28; + case -7: + return -42; + case -19: + return -38; + default: + return -40; + } +} + +int SOGetPeerName(int s, void* sockAddr) { + SONode* node; + IPInfo* info; + TCPInfo* tcp; + UDPInfo* udp; + s32 rc; + + if (State != 1) { + return -39; + } + + ASSERT(sockAddr); + ASSERT(sockAddr == NULL || sizeof(SOSockAddrIn) <= ((SOSockAddr*) sockAddr)->len); + if (sockAddr == NULL || sizeof(SOSockAddrIn) <= ((SOSockAddr*) sockAddr)->len) { + return -28; + } + + node = GetNode(s, &info); + if (node == NULL || info == NULL) { + return -8; + } + + switch (info->proto) { + case IP_PROTO_UDP: + udp = (UDPInfo*)info; + rc = UDPGetRemoteSocket(udp, (IPSocket*)sockAddr); + break; + case IP_PROTO_TCP: + tcp = (TCPInfo*)info; + rc = TCPGetRemoteSocket(tcp, (IPSocket*)sockAddr); + break; + default: + PutNode(node); + return -8; + } + + PutNode(node); + if (rc < 0) { + return -8; + } + + if (((SOSockAddrIn*) sockAddr)->port == 0) { + return -56; + } + + return 0; +} + +int SOGetSockName(int s, void* sockAddr) { + SONode* node; + IPInfo* info; + TCPInfo* tcp; + UDPInfo* udp; + s32 rc; + + if (State != 1) { + return -39; + } + + ASSERT(sockAddr); + ASSERT(sockAddr == NULL || sizeof(SOSockAddrIn) <= ((SOSockAddr*) sockAddr)->len); + if (sockAddr == NULL || sizeof(SOSockAddrIn) <= ((SOSockAddr*) sockAddr)->len) { + return -28; + } + + node = GetNode(s, &info); + if (node == NULL || info == NULL) { + return -8; + } + + switch (info->proto) { + case IP_PROTO_UDP: + udp = (UDPInfo*)info; + rc = UDPGetLocalSocket(udp, (IPSocket*)sockAddr); + break; + case IP_PROTO_TCP: + tcp = (TCPInfo*)info; + rc = TCPGetLocalSocket(tcp, (IPSocket*)sockAddr); + break; + default: + PutNode(node); + return -8; + } + + PutNode(node); + if (rc < 0) { + return -8; + } + + return 0; +}